关于深拷贝和浅拷贝的区别,主要在对于引用类型的成员的拷贝上,浅拷贝只是简单的复制引用的地址,深拷贝会生成一个完全独立的对象,包括对象内的引用成员。
浅拷贝:Object类提供了一个MemberwiseClone方法,一般是基于它来实现。
深拷贝:要求对象要实现Serializable特性,表明它是可以被序列化的。利用对象的序列化和反序列化来实现深度拷贝。
完整的例子如下:
using System;
using System.Collections.Generic;
using System.Text;
namespace CsharpBase
{
class CloneDemo
{
public static void Run()
{
People parent = new People("zhang", "30");
parent.type = "old";
parent.child.Name = "zhang xiao";
parent.child.Age = "1";
parent.PrintInfo();
//浅拷贝
People shallowParent = (People)parent.Clone();
//深拷贝
People deepParent = parent.DeepClone();
shallowParent.type = "shallow";
shallowParent.Name = "shallow zhang";
//浅拷贝对于引用型成员child只会复制其所在堆的首地址,不会进行真正的内容拷贝
//所以在这里shallowParent.child.Name的改变会导致parent.child.Name的改变,因为他们的
//child都指向了同一片内存区
shallowParent.child.Name = "shallow zhang xiao";
shallowParent.PrintInfo();
parent.PrintInfo();
deepParent.type = "Deep";
deepParent.Name = "Deep zhang";
//深拷贝能实现真正的拷贝
deepParent.child.Name = "Deep zhang xiao";
deepParent.PrintInfo();
parent.PrintInfo();
Console.ReadKey();
}
[Serializable]
private class People : ICloneable
{
public string type;
public string Name;
public string Age;
public Child child = new Child();
public People(string name, string age)
{
Name = name;
Age = age;
}
//浅拷贝
private People ShallowClone()
{
return (People)Clone();
}
#region ICloneable
public object Clone()
{
return this.MemberwiseClone();
}
#endregion
//深拷贝
public People DeepClone()
{
System.IO.Stream stream = new System.IO.MemoryStream();
System.Runtime.Serialization.IFormatter formater = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
formater.Serialize(stream, this);
stream.Seek(0, System.IO.SeekOrigin.Begin);
return (People)formater.Deserialize(stream);
}
public void PrintInfo()
{
System.Diagnostics.Debug.WriteLine("type:" + type);
System.Diagnostics.Debug.WriteLine("parent:" + Name);
System.Diagnostics.Debug.WriteLine("child:" + child.Name);
System.Diagnostics.Debug.WriteLine("---------------");
}
}
[Serializable]
private class Child
{
public string Name;
public string Age;
}
}
}
注意,Child类也必须有Serializable特性,否则formater.Serialize(stream, this);的时候会抛出SerializableException异常。
运行结果:
type:old
parent:zhang
child:zhang xiao
---------------
type:shallow
parent:shallow zhang
child:shallow zhang xiao
---------------
type:old
parent:zhang
child:shallow zhang xiao //这里被改变了
---------------
type:Deep
parent:Deep zhang
child:Deep zhang xiao
---------------
type:old
parent:zhang
child:shallow zhang xiao //这里没变
---------------