Clive Francis
Clive Francis

Reputation: 13

C# clone from supertype

Abstract supertype Animal has many subtypes, Cat, Dog etc. These subtypes have only a constructor and overrides of virtual methods found in Animal - ie they have NO Properties or Methods unique to themselves. Class Zoo has many references to, and Lists of Animals, but does not know about or will ever need to know about Cats, Dogs etc. What is the most best way of enabling deep copying of Zoo? , preferably with little or no new code in Cat, Dog etc.

Upvotes: 1

Views: 238

Answers (2)

Bradley Uffner
Bradley Uffner

Reputation: 16991

One quick and easy way to deeply clone an object is to serialize it to a MemoryStream and then deserialize it back to an object graph. The deserialized copy will be a deep-cloned graph with no references to the original objects. It can be a bit more memory and CPU intensive than manually cloneining the object, but it is significantly less coding work; the end result is usually acceptable.

Here is one implementation taken from CodeProject:

using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;     

/// <span class="code-SummaryComment"><summary></span>
/// Provides a method for performing a deep copy of an object.
/// Binary Serialization is used to perform the copy.
/// <span class="code-SummaryComment"></summary></span>
public static class ObjectCopier
{
 /// <span class="code-SummaryComment"><summary></span>
 /// Perform a deep Copy of the object.
 /// <span class="code-SummaryComment"></summary></span>
 /// <span class="code-SummaryComment"><typeparam name="T">The type of object being copied.</typeparam></span>
 /// <span class="code-SummaryComment"><param name="source">The object instance to copy.</param></span>
 /// <span class="code-SummaryComment"><returns>The copied object.</returns></span>
 public static T Clone<T>(T source)
 {
  if (!typeof(T).IsSerializable)
  {
    throw new ArgumentException("The type must be serializable.", "source");
  }

  // Don't serialize a null object, simply return the default for that object
  if (Object.ReferenceEquals(source, null))
  {
    return default(T);
  }

  IFormatter formatter = new BinaryFormatter();
  Stream stream = new MemoryStream();
  using (stream)
  {
    formatter.Serialize(stream, source);
    stream.Seek(0, SeekOrigin.Begin);
    return (T)formatter.Deserialize(stream);
  }
 }
}

It can be called like this:

ObjectCopier.Clone(objectBeingCloned);

Upvotes: 1

Patrick Hofman
Patrick Hofman

Reputation: 156978

If your concern is that you need to create a new Clone implementation, just to get the right type (since the type of this in a base class is a moving target), you could use Activator.CreateInstance to create a new instance of the current type, for all types that override Animal:

var copy = (Animal)Activator.CreateInstance(this.GetType());

copy.HasClaws = this.HasClaws; // copy Animal properties

You need a parameterless constructor in order to make this Activator.CreateInstance call work.

Upvotes: 3

Related Questions