2012-04-27 22:05:19|?次阅读|上传:wustguangh【已有?条评论】发表评论
利用受保护的方法System.Object.MemberwiseClone()可以进行浅度复制,也就是说对于含有引用类型字段的对象来说,进行浅度复制意味着复制的对象和源对象存在这相同的引用。如果源对象的引用变量的值发生改变,那么被复制的对象的成员值也会发生变化。有很多适合这都不是我们希望看到的结果, 所以有必要对对象进行深度复制,这可以通过ICloneable接口的Clone方法实现,它通过创建新对象的方法进行深度复制。在比较复杂的对象系统调用Clone()是一个递归的过程,这次复制的对象和源对象是独立的。
浅度复制对引用类型只复制引用,及复制后源引用与目标引用的引用类型是指向都一个对象,操作其中一个,另外一个也会受影响;深度复制则源引用和目标引用对 象的是两个不同的对象,操作互不影响;浅度复制是直接完全把栈的内容拷贝一份而已,而深度复制把对应的堆内容也拷贝了一份;浅度复制可以直接调用 System.Object.MemberwiseClone()这个受保护的方法就可以了;而深度引用根据C#的规范实现ICloneable接口即可。
首先给出第一个使用System.Object.MemberwiseClone()实现浅度复制的实例,在Cloner中,我们只定义了值类型的成员变量Val:
public class Cloner { public int Val; public Cloner(int newVal) { Val = newVal; } public object GetCopy() { return MemberwiseClone(); } }
然后添加测试代码如下:
static void Main() { Cloner mySource = new Cloner(5); Cloner myTarget = (Cloner)mySource.GetCopy(); Console.WriteLine("mySource.Val = {0}", mySource.Val); Console.WriteLine("myTarget.Val = {0}", myTarget.Val); mySource.Val = 2; Console.WriteLine("mySource.Val = {0}", mySource.Val); Console.WriteLine("myTarget.Val = {0}", myTarget.Val); Console.ReadKey(); }
程序的输出结果如下:
我们发现,这种简单的值类型域的复制,即使改变源对象的值也不会影响复制对象的值,也就是说我们创建了一个新的对象实例,下面我们在来看一个包含引用类型的实例,实例代码和测试代码如下:
using System; using System.Collections.Generic; using System.Linq; using System.Windows.Forms; namespace Test5 { static class Program { public class Content { public int Val; } public class Cloner { public Content MyContent = new Content(); public Cloner(int newVal) { MyContent.Val = newVal; } public object GetCopy() { return MemberwiseClone(); } } /// <summary> /// 应用程序的主入口点。 /// </summary> [STAThread] static void Main() { Cloner mySource = new Cloner(5); Cloner myTarget = (Cloner)mySource.GetCopy(); Console.WriteLine("mySource.MyContent.Val = {0}", mySource.MyContent.Val); Console.WriteLine("myTarget.MyContent.Val = {0}", myTarget.MyContent.Val); mySource.MyContent.Val = 2; Console.WriteLine("mySource.MyContent.Val = {0}", mySource.MyContent.Val); Console.WriteLine("myTarget.MyContent.Val = {0}", myTarget.MyContent.Val); Console.ReadKey(); } } }
程序的执行结果如下:
从结果中你可以发现,当改变源对象mySource.MyContent.Val的引用类型域的值后通过阴影复制得到的对象myTarget的引用类型域的值同时发生了 改变。这是因为使用MemberwiseClone()只能实现浅度复制,mySource.MyContent引用了与myTarget.MyContent相同的对象实例。为了实现彻底复制,即复制对象与源对象相互独立、互不影响,需要执行深度复制。修改上面的 GetCopy()方法也可以进行深度复制,但最好使用.NET Framework的标准方式。为此,实现ICloneable接口,该接口有一个方法Clone(),这个方法不带参数,返回一个对象类型,其签名和上 面使用的GetCopy()方法相同。下面给出实际的源代码和测试代码:
using System; using System.Collections.Generic; using System.Linq; using System.Windows.Forms; namespace Test5 { static class Program { public class Content { public int Val; } public class Cloner : ICloneable { public Content MyContent = new Content(); public Cloner(int newVal) { MyContent.Val = newVal; } #region ICloneable 成员 public object Clone() { Cloner clonedCloner = new Cloner(MyContent.Val); return clonedCloner; } #endregion } /// <summary> /// 应用程序的主入口点。 /// </summary> [STAThread] static void Main() { Cloner mySource = new Cloner(5); Cloner myTarget = (Cloner)mySource.Clone(); Console.WriteLine("mySource.MyContent.Val = {0}", mySource.MyContent.Val); Console.WriteLine("myTarget.MyContent.Val = {0}", myTarget.MyContent.Val); mySource.MyContent.Val = 2; Console.WriteLine("mySource.MyContent.Val = {0}", mySource.MyContent.Val); Console.WriteLine("myTarget.MyContent.Val = {0}", myTarget.MyContent.Val); Console.ReadKey(); } } }
程序的运行结果如下:
从结果你可以看出,通过深度复制,两个对象已经没有任何关系了,对第一个对象的改变没有影响到第二个对象。这里使用的是包含在源Cloner对象(MyContent)中的Content对象的Val字段去创建一个新的Cloner对象。这个域是一个值类型所以不需要进行深度复制。通过ICloneable.Clone方法实现除MemberwiseClone所提供的克隆之外的克隆。