C# 深度复制
通过下面的GetCopy()方法,介绍了如何使用受保护的方法System.Object.MemberwiseClone()进行浅度复制。
public class Cloner
{
public int Val;
public Cloner{int newVal) => Val = newVal;
public object GetCopy() => MemberwiseClone();
}
假定有一些引用类型的字段,而不是值类型的字段(例如,对象):
public class Content
{
public int Val;
}
public class Cloner
{
public Content MyContent = new Content();
public Cloner(int newVal) => MyContent.Val s newVal;
public object GetCopy() => MemberwiseClone();
}
此时,通过GetCopyO得到的浅度复制包括一个字段,它引用的对象与源对象相同。以下代码使用这个Cloner类来说明浅度复制引用类型的结果:
Cloner mySource = new Cloner(5);
Cloner myTarget = (Cloner)mySource.GetCopy();
WriteLine($"myTarget.MyContent.Val = {myTarget-MyContent.Val}");
mySource.MyContent.Val =2;
WriteLine($"myTarget.MyContent.Val = (myTarget .MyContent.Val}");
第4行把一个值赋给mySource.MyContent.Val,它是源对象中公共字段MyContent的公共字段Val。这也改变了 myTarget.MyContent.Val 的值。这是因为 mySource.MyContent 引用了与 myTargetMyContent 相同的对象实例。上述代码的输出结果如下:
myTarget.MyContent.Val = 5
myTarget.MyContent.Val = 2
为解决这个问题,需要执行深度复制。修改上面的GetCopyO方法就可以进行深度复制,但最好使用.NET Framework的标准方式:实现ICloneable接口,该接口有一个Clone()方法;这个方法不带参数,返回一个object类型的结果,其签名和上面使用的GetCopy()方法相同。
为修改上面的类,可使用下面的深度复制代码:
public class Content
{
public int Val;
}
public class Cloner : ICloneable
{
public Content MyContent = new Content 0;
public Cloner(int newVal) => MyContent.Val = newVal;
public object Clone()
{
Cloner clonedCloner = new Cloner(MyContent.Val);
return clonedCloner;
}
}
其中使用包含在源Cloner对象中的Content对象(MyContent)的Val字段,创建了一个新对象Cloner。这个字段是一个值类型,所以不需要深度复制。
使用与上面类似的代码来测试浅度复制,但用CloneO替代GetCopy(),得到如下结果:
myTarget.MyContent.Val = 5
myTarget,MyContent.Val = 5
这次包含的对象是独立的。注意有时在比较复杂的对象系统中,调用Clone()是一个递归过程。例如,如果Cloner类的MyContent字段也需要深度复制,就要使用下面的代码:
public class Cloner : ICloneable
{
public Content MyContent = new Content();
...
public object Clone()
{
Cloner clonedCloner = new Cloner();
clonedCloner.MyContent = MyContent.Clone();
return clonedCloner;
}
}
这里调用了默认的构造函数,以便简化创建新对象Cloner的语法。为使这段代码能正常工作,还需要在 Content 类上实现 ICloneable 接口。
点击加载更多评论>>