一、浅层拷贝,就是只拷贝类的第一层成员,而且如果成员是引用类型,则引用同一份。
1、手动自己实现
class Person:ICloneable { public int Id { get; set; } public string Name { get; set; } public Dept Dept { get; set; } public object Clone() { Person person2 = new Person(); person2.Id = this.Id; person2.Name = this.Name; person2.Dept = this.Dept; return person2; } } class Dept { public string Name { get; set; } public Dept Clone() { Dept dept = new Dept(); dept.Name = this.Name; return dept; } } class Program { public static void Main() { Person person1 = new Person(); person1.Id = 1; person1.Name = "张三"; Dept dept = new Dept(); dept.Name = "程序员"; person1.Dept = dept; // person2对象和person1对象的Person对象指向同一个Person对象,这就是浅拷贝 Person person2 = (Person)person1.Clone(); } }
2、微软提供了一个浅层拷贝的方法:System.Object类的MemberwiseClone()
class Person:ICloneable { public int Id { get; set; } public string Name { get; set; } public Dept Dept { get; set; } public object Clone() { //Person person2 = new Person(); //person2.Id = this.Id; //person2.Name = this.Name; //person2.Dept = this.Dept; //return person2; Person person2 = (Person)this.MemberwiseClone(); return person2; } } class Dept { public string Name { get; set; } public Dept Clone() { Dept dept = new Dept(); dept.Name = this.Name; return dept; } } class Program { public static void Main() { Person person1 = new Person(); person1.Id = 1; person1.Name = "张三"; Dept dept = new Dept(); dept.Name = "程序员"; person1.Dept = dept; // person2对象和person1对象的Person对象指向同一个Person对象,这就是浅拷贝 Person person2 = (Person)person1.Clone(); Console.WriteLine(object.ReferenceEquals(person1, person2)); // 输出False Console.WriteLine(object.ReferenceEquals(person1.Dept, person2.Dept)); // 输出True Console.ReadKey(); } }
二、深层拷贝,把对象引用的所有直接、间接的对象都拷贝一份。完全的一份拷贝。
1、使用IO流和序列化实现深层拷贝
[Serializable] class Person:ICloneable { public int Id { get; set; } public string Name { get; set; } public Dept Dept { get; set; } public object Clone() { BinaryFormatter formatter = new BinaryFormatter(null,new StreamingContext(StreamingContextStates.Clone)); object cloneObject; using (MemoryStream stream = new MemoryStream()) { formatter.Serialize(stream, this); //stream.Position = 0; stream.Seek(0, SeekOrigin.Begin); cloneObject = formatter.Deserialize(stream); } return cloneObject; } } [Serializable] class Dept { public string Name { get; set; } public Dept Clone() { Dept dept = new Dept(); dept.Name = this.Name; return dept; } } class Program { public static void Main() { Person person1 = new Person(); person1.Id = 1; person1.Name = "张三"; Dept dept = new Dept(); dept.Name = "程序员"; person1.Dept = dept; Person person2 = (Person)person1.Clone(); Console.WriteLine(object.ReferenceEquals(person1, person2)); // 输出False Console.WriteLine(object.ReferenceEquals(person1.Dept, person2.Dept)); // 输出False Console.ReadKey(); } }
2、通过反射实现深层拷贝:http://www.codeproject.com/Articles/3441/Base-class-for-cloning-an-object-in-C
/// <summary> /// <b>BaseObject</b> class is an abstract class for you to derive from. <br> /// Every class that will be dirived from this class will support the <b>Clone</b> method automaticly.<br> /// The class implements the interface <i>ICloneable</i> and there for every object that will be derived <br> /// from this object will support the <i>ICloneable</i> interface as well. /// </summary> public abstract class BaseObject : ICloneable { /// <summary> /// Clone the object, and returning a reference to a cloned object. /// </summary> /// <returns>Reference to the new cloned object.</returns> public object Clone() { //First we create an instance of this specific type. object newObject = Activator.CreateInstance(this.GetType()); //We get the array of fields for the new type instance. FieldInfo[] fields = newObject.GetType().GetFields(); int i = 0; foreach (FieldInfo fi in this.GetType().GetFields()) { //We query if the fiels support the ICloneable interface. Type ICloneType = fi.FieldType.GetInterface("ICloneable", true); if (ICloneType != null) { //Getting the ICloneable interface from the object. ICloneable IClone = (ICloneable)fi.GetValue(this); //We use the clone method to set the new value to the field. fields[i].SetValue(newObject, IClone.Clone()); } else { //If the field doesn't support the ICloneable interface then just set it. fields[i].SetValue(newObject, fi.GetValue(this)); } //Now we check if the object support the IEnumerable interface, so if it does //we need to enumerate all its items and check if they support the ICloneable interface. Type IEnumerableType = fi.FieldType.GetInterface("IEnumerable", true); if (IEnumerableType != null) { //Get the IEnumerable interface from the field. IEnumerable IEnum = (IEnumerable)fi.GetValue(this); //This version support the IList and the IDictionary interfaces to iterate //on collections. Type IListType = fields[i].FieldType.GetInterface("IList", true); Type IDicType = fields[i].FieldType.GetInterface("IDictionary", true); int j = 0; if (IListType != null) { //Getting the IList interface. IList list = (IList)fields[i].GetValue(newObject); foreach (object obj in IEnum) { //Checking to see if the current item support the ICloneable interface. ICloneType = obj.GetType().GetInterface("ICloneable", true); if (ICloneType != null) { //If it does support the ICloneable interface, we use it to set the clone of //the object in the list. ICloneable clone = (ICloneable)obj; list[j] = clone.Clone(); } //NOTE: If the item in the list is not support the ICloneable interface then // in the cloned list this item will be the same item as in the original list //(as long as this type is a reference type). j++; } } else if (IDicType != null) { //Getting the dictionary interface. IDictionary dic = (IDictionary)fields[i].GetValue(newObject); j = 0; foreach (DictionaryEntry de in IEnum) { //Checking to see if the item support the ICloneable interface. ICloneType = de.Value.GetType().GetInterface("ICloneable", true); if (ICloneType != null) { ICloneable clone = (ICloneable)de.Value; dic[de.Key] = clone.Clone(); } j++; } } } i++; } return newObject; } } class Person : BaseObject { public int Id { get; set; } public string Name { get; set; } public Dept Dept { get; set; } } class Dept { public string Name { get; set; } } class Program { public static void Main() { Person person1 = new Person(); person1.Id = 1; person1.Name = "张三"; Dept dept = new Dept(); dept.Name = "程序员"; person1.Dept = dept; Person person2 = (Person)person1.Clone(); Console.WriteLine(object.ReferenceEquals(person1, person2)); // 输出False Console.WriteLine(object.ReferenceEquals(person1.Dept, person2.Dept)); // 输出False Console.ReadKey(); } }
三、总结:浅层拷贝。对象是新的对象,对象的值类型重新拷贝,引用类型的字段、属性还是指向相同的对象;深层拷贝。对象是新的对象,对象的值类型重新拷贝,引用类型的字段、属性也指向对象的一份拷贝。