日期:2014-05-18  浏览次数:21125 次

C#中Clone方法的链式复制实现

?

  大多数稍微有过一些编程实践的C#初学者都应该听说过“浅层复制”和“深层复制”的区别,如果尚不清楚的盆友还是先去搜索一下相关的专题,我在这里不多说,本文主要内容是记录一下区别于前两者的另外一种在有较复杂的类层次情况下的复制方式。

  比如有如下类的声明:(代码1)

	public class ClassOne
	{
		public int Value = 0;
	}

	public class ClassTwo : ICloneable
	{
		private ClassOne inner = new ClassOne();

		public object Clone()
		{
			return this.MemberwiseClone();
		}
	}

?

  即第二个类将第一个类作为私有成员进行封装。此时若直接调用ClassTwo对象的Clone()方法则实际上是进行了ClassTwo的浅层复制。
  如果想通过Clone()方法进行深层复制,则需要进行如下修改:(代码2)

	public class ClassOne
	{
		public int Value = 0;
	}

	public class ClassTwo : ICloneable
	{
		private ClassOne one = new ClassOne();

		public object Clone()
		{
			ClassTwo clone = (ClassTwo)this.MemberwiseClone();
			clone.one = new ClassOne();
			clone.one.Value = this.one.Value;
			return clone;
		}
	}

?

  写到这里这两个类的确已经相安无事了。然而事情没这么简单,接下来如果从ClassTwo派生出一个子类ClassThree如下:(代码3)

	public class ClassThree : ClassTwo
	{
		public readonly int Key = 100;
		private ClassOne two = new ClassOne();

		...
	}

?

  此时如果想要通过Clone()对ClassThree进行深层复制该如何做呢?有些和我之前一样小白的盆友们会立刻想到如下修改该方式:(代码4)

	public class ClassThree : ClassTwo, ICloneable
	{
		public readonly int Key = 100;
		private ClassOne two = new ClassOne();

		public new object Clone()
		{
			ClassThree clone = (ClassThree)this.MemberwiseClone();
			clone.two = new ClassOne();
			clone.two.Value = this.two.Value;
			return clone;
		}
	}

?

?

  稍微有些经验的盆友马上就会发现,这样的修改并不能正确的实现深层复制的目的,因为ClassTwo中的成员ClassTwo.one是private的,无法直接访问,而this.MemberwiseClone()方法只会将其进行浅层复制。
  于是马上就能想到的另一种修改方法如下:(代码5)

	public class ClassThree : ClassTwo, ICloneable
	{
		public readonly int Key = 100;
		private ClassOne two = new ClassOne();

		public new object Clone()
		{
			ClassThree clone = (ClassThree)base.Clone();
			clone.Key = this.Key;
			clone.two = new ClassOne();
			clone.two.Value = this.two.Value;
			return clone;
		}
	}

?

  看似完成了需求,但实际上这次的修改根本无法便已成功,原因出在第9行代码,因为ClassThree.Key是只读的,无法在构造函数以外的方法中对齐进行赋值。
  代码4和代码5的思路都不对,岂不是进入死胡同了?其实不然,经过我的简单试验发现只要删除代码4中的第9行就可以完美的实现我们的深层复制需求,完整代码如下:(代码6)

	public class ClassOne
	{
		public int Value = 0;
	}

	public class ClassTwo : ICloneable
	{
		private ClassOne one = new ClassOne();

		public object Clone()
		{
			ClassTwo clone = (ClassTwo)this.MemberwiseClone();
			clone.one = new ClassOne();
			clone.one.Value = this.one.Value;
			return clone;
		}
	}

	public class ClassThree : ClassTwo, ICloneable
	{
		public readonly int Key = 100;
		private ClassOne two = new ClassOne();

		public new object Clone()
		{
			ClassThree clone = (ClassThree)base.Clone();
			clone.two = new ClassOne();
			clone.two.Value = this.two.Value;
			return clone;
		}
	}

?

  其实原因很简单,在执行代码6中第26行时,.NET框架首先执行了其父类的Clone()方法,在本例中则是实现了对父类的深层复制,接下来是隐式的对当前类中的除父类中以外的非静态成员进行了浅层复制,即.NET框架已经悄悄的帮我们完成了clone.Key = this.Key的操作,真相大白,功德圆满。

  总结,在执行base.Clone()的实际操作可分解为:首先执行了其父类的Clone()方法,然后隐式的对当前类中的除父类中以外的非静态成员进行了浅层复制,最后返回类型与this相同的经过链式复制新对象。

?

?

?

?

作者:KeViNOne

本文版权归作者,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接及作者主页链接,否则保留追究法律责任的权利。