继承ICloneable接口后,内部克隆实现经常用到 MemberwiseClone() 来实现。书上看到解释,说这是浅克隆,对于值类型,正常执行克隆操作,而对于引用类型,则是将引用进行了克隆。在新的对象中仅保存了原对象的一个引用,带来的副作用就是,新对象中修改了值,新对象中的值也随着变化。
根据这种解释自己写了实例进行尝试:如下声明一个People类,包括三个属性:int、string、enum三种类型。
View Code
1 internal class People : ICloneable 2 { 3 public int Age { get; set; } 4 public string Name { get; set; } 5 public Sex Sex { get; set; } 6 7 public object Clone() 8 { 9 return MemberwiseClone();10 }11 12 public override string ToString()13 {14 return String.Format("Name: {0}, Age: {1}, Sex: {2}, HashCode: {3}.",Name,Age,Sex,GetHashCode());15 }16 }
然后实现对象的克隆,并在修改新对象后输出
View Code
private static void Main(string[] args) { var people1 = new People {Age = 1, Name = "Tom", Sex = Sex.Male}; Console.WriteLine(people1.ToString()); var people2 = (People)people1.Clone(); people2.Age = 2; people2.Name = "Jim"; people2.Sex=Sex.Female; Console.WriteLine(people1.ToString()); Console.WriteLine(people2.ToString()); }
输出如图:
表示新的克隆对象与源对象并不是同一个引用,内部的string、enum等类型也互不影响,是两个不同的内存区域。书中这部分说法是错误的。
对于复杂的引用类型,则是另外的情形。新建类型测试:
View Code
1 class MyClass:ICloneable 2 { 3 public int ID { get; set; } 4 5 public People Teacher { get; set; } 6 7 public object Clone() 8 { 9 return MemberwiseClone();10 }11 12 public override string ToString()13 {14 return String.Format("ID:{4} Name: {0}, Age: {1}, Sex: {2}, HashCode: {3}, Teacher HashCode:{5}.", Teacher.Name, Teacher.Age, Teacher.Sex, GetHashCode(),ID,Teacher.GetHashCode());15 }16 }
实现对象的克隆,并在修改新对象后输出
View Code
1 var class1 = new MyClass { ID = 1, Teacher = new People { Age = 1, Name = "Tom", Sex = Sex.Male } };2 Console.WriteLine(class1.ToString());3 var class2 = (MyClass)class1.Clone();4 class2.ID = 2;5 class2.Teacher.Age = 2;6 class2.Teacher.Name = "Jim";7 class2.Teacher.Sex = Sex.Female;8 Console.WriteLine(class1.ToString());9 Console.WriteLine(class2.ToString());
此次输出结果如图:
结果表示,对象的克隆生成了一个新的不同的类型,值类型在两个对象中存在两份,修改互不影响。而引用类型则只存在一份实例,Teacher HashCode相同,修改一个对象中的引用属性,会影响到另一个对象。这就是所谓的“浅拷贝”。