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 = newVal;
   public object GetCopy() => MemberwiseClone();
}

   此时,通过GetCopy()得到的浅度复制包括一个字段,它引用的对象与源对象相同。以下代码使用这个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引用了与myTarget.MyContent相同的对象实例。上述代码的输出结果如下:

myTarget.MyContent.Val = 5
myTarget.MyContent.Val = 2

  为了解决这个问题,需要执行深度复制。修改上面的GetCopy()方法就可以进行深度复制,但最好使用.NETFramework的标准方式:实现ICloneable接口,该接口有一个Clone()方法:这个方法不带参数,返回一个object类型的结果,其签名和上面使用的GetCopy()方法相同。

  为了修改上面的类,可使用下面的深度复制代码:

public class Content
{
   public int Val;
}
public class Cloner : ICloneacle
{
   public Content MyContent => new Content();
   public Cloner(int newVal) => MyContent.Val = newVal;
   public object Clone()
   {
      Cloner clonedCloner = new Cloner(MyContent.Val);
      return cloneCloner;
   }
} 

  其中使用包含在源Cloner对象中的Content对象(MyContent)的Val字段,创建了一个新对象Cloner。这个字段是一个值类型,所以不需要深度复制。

  使用与上面类似的代码来测试浅度复制,但用Clone()替代GetCopy(),得到如下结果:

myTarget.MyContent.Val = 5
myTarget.MyContent.Val = 5

  这次包含的对象是独立的。注意有时在比较复杂的对象系统中,调用Clone()是一个递归过程。例如,如果Cloner类的MyContent字段也需要深度复制,就要使用下面的代码:

public class Cloner : IClonerable
{
   public Content myContent = new Content();
   ...
   public object Clone()
   {
      Cloner clonedCloner = new Cloner();
      clonedCloner.MyContent = MyContent.Clone();
      return cloneCloner;
   }
}

  这里调用了默认的构造函数,以便简化创建新对象Cloner的语法。为使这段代码能正常工作,还需要再Content类上实现ICloneable接口。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值