C#中的深复制与浅复制
C#中分为值类型和引用类型,值类型的变量直接包含其数据,而引用类型的变量则存储对象的引用。
对于值类型,每个变量都有自己的数据副本,对一个变量的操作不可能影响到另一个变量。如
class Program { static void Main(string[] args) { int a = 3; int b=a; a = 5; Console.WriteLine("a={0},b={1}",a,b); Console.ReadKey(); } }
输出为:
a=5,b=3
而对于引用类型,两个变量可能引用同一个对象,因此对一个变量的操作可能影响到另一个变量所引用的对象。
public class A { public int param; public A(int i) { this.param = i; } } A a1 = new A(5); A a2 = a1; a1.param = 10; Console.WriteLine("a1.param={0},a2.param={1}",a1.param,a2.param); Console.ReadKey();
输出为:
a1.param=10,a2.param=10
可见改变了a1中的param值,也会同样改变a2中的param值,因为它们指向的是同一个实例,其实就是同一个。
浅复制:实现浅复制需要使用Object类的MemberwiseClone方法创建一个浅表副本。
深复制:需实现ICloneable接口中的Clone方法,重新实例化一个对象作为返回值。
对于复制对象中的值类型,结果正确:
public class Person :ICloneable { private int age; public int Age { get { return age; } set { this.age = value; } } public Person(int i) { this.age = i; } public object Clone() { //return this.MemberwiseClone(); return new Person(this.age) as object; } } Person p1 = new Person(5); Person p2 = (Person)p1.Clone(); p1.Age = 10; Console.WriteLine("p1.age={0},p2.age={1}",p1.Age,p2.Age); Console.ReadKey();
利用 return this.MemberwiseClone()和return new Person(this.age) as object输出的值均为:
p1.age=10,p2.age=5
但是若是复制对象中的引用类型时,浅复制就会出现问题,如下:
public class Education { public int score; } public class Person:ICloneable { public Education education=new Education (); public Person(int i) { education.score = i; } public object Clone() { return this.MemberwiseClone(); //return new Person(this.education.score) as object; } }
Person p1 = new Person(59); Person p2 = (Person)p1.Clone(); p1.education.score = 99; Console.WriteLine("p1.education.score={0},p2.education.score={1}", p1.education.score, p2.education.score); Console.ReadKey();
当用return this.MemberwiseClone()时,即用浅复制时,输出为:
p1.education.score=99,p2.education.score=99
这与原来的代码意图不符,当用return new Person(this.education.score) as object时,输出为
p1.education.score=99,p2.education.score=59