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所提供的克隆之外的克隆。