C# Clone方法

clone是深拷贝,copy是浅拷贝,如果是值类型的话是没什么区别的,如果是引用类型的话深拷贝拷贝的事整个对象的数据,而浅拷贝仅仅拷贝对象的引用。因为类的实例是引用类型,要想用原有的类中的实例的数据的话,既要想创建原对象的一个副本的话,只能用clone方法。Clone方法分为深clone和浅clone 。

实现Clone的方法

手工克隆

一个能够保证对象完全按照你所想的那样进行克隆的方式是手工克隆对象的每一个域(field)。这种方式的缺点是麻烦而且容易出错:如果你在类中增加了一个域,你很可能会忘记更新Clone方法。还要在克隆引用对象指向原始对象的时候,注意避免无限循环引用。.

使用MemberWiseClone方法

MemberWiseClone是Object类的受保护方法,能够通过创建一个新对象,并把所有当前对象中的非静态域复制到新对象中,从而创建一个浅拷贝。对于值类型的域,进行的是按位拷贝。对于引用类型的域,引用会被赋值而引用的对象则不会。因此,原始对象及其克隆都会引用同一个对象。注意,这种方法对派生类都是有效的,也就是说,你只需在基类中定义一次Clone方法。

用反射进行克隆

用反射进行克隆是使用Activator.CreateInstance方法来创建一个相同类型的新对象,然后用反射对所有域进行浅拷贝。这种方法的优点是它是全自动的,不需要在对象中添加或删除成员的时候修改克隆方法。另外它也能被写成提供深拷贝的方法。缺点是使用了反射,因此会比较慢,而且在部分受信任的环境中是不可用的。

使用序列化进行克隆

克隆一个对象的最简单的方法是将它序列化并立刻反序列化为一个新对象。和反射方法一样,序列化方法是自动的,无需在对对象成员进行增删的时候做出修改。缺点是序列化比其他方法慢,甚至比用反射还慢,所有引用的对象都必须是可序列化的(Serializable)。另外,取决于你所使用的序列化的类型(XML,SOAP,二进制)的不同,私有成员可能不能像期望的那样被克隆。

代码

///
/// Reference Article http://www.codeproject.com/KB/tips/SerializedObjectCloner.aspx
/// Provides a method for performing a deep copy of an object.
/// Binary Serialization is used to perform the copy.
///
public static class ObjectCopier
{
    ///
    /// Perform a deep Copy of the object.
    ///
    /// The type of object being copied.
    /// The object instance to copy.
    /// The copied object.
    public static T Clone(this 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);
       }
    }
}