Since most types in the .NET framework and in the class
libraries you develop yourself are reference types, assigning one instance to
another would have the two pointing to the same object. Because of this, the
need to clone object is quite common within .NET applications. Out of the box, System.Object has a MemberwiseClone method which creates a
shallow copy of the object. A shallow copy is a copy of the class members
without copies of objects further down in the object graph. You can implement
the IClonable interface, which
defines a Clone method, to
explicitly support deep cloning of your classes, but still client code has no
guarantee that a class implementing the ICloneable
interface creates a deep clone of an instance.
If you have a large class library, such as a domain model, implementing ICloneable will require much work and
you’ll also have to ensure that your cloning algorithm functions as intended
whenever you change your class. An option that I’ve seen many developers resort
to is to use reflection to generalize the cloning algorithm. Reflection has
some overhead, but it isn’t as slow as many people think. How ever, if you find
the performance overhead of using reflection acceptable, there is a much easier
and simpler way to deep clone an object.
As long as your types are serializable, you can use
serialization to clone the object. Below is an example of a method that creates
a deep clone of an object by serializing the instance to a MemoryStream, and then creates a
cloned object by deserializing the stream to a new instance.
public static class XeroxMachine
{
public static T Clone<T>(T source)
{
if (!typeof(T).IsSerializable)
{
throw new
ArgumentException("The type must be serializable.","source");
}
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);
}
}
}
Generics don’t have a way of restricting a generic type parameter
to be serializable, therefore I’m checking asserting that the type is serializable
before I clone it.
By using the XeroxMachine
helper class, the ICloneable
interface is a breeze to implement.
[Serializable]
public class MyClass :
ICloneable
{
public object Clone()
{
return
XeroxMachine.Clone(this);
}
}
This technique works for every serializable type, and you’re
guaranteed to get a true, deep copied clone of the object. Cloning an object
this way is of course less efficient in terms of performance than writing your
own type specific Clone method,
but it is much more efficient when it comes to the time it takes to write the
code.