深层拷贝和浅层拷贝

一、浅层拷贝,就是只拷贝类的第一层成员,而且如果成员是引用类型,则引用同一份。

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();
        }
    }

三、总结:浅层拷贝。对象是新的对象,对象的值类型重新拷贝,引用类型的字段、属性还是指向相同的对象;深层拷贝。对象是新的对象,对象的值类型重新拷贝,引用类型的字段、属性也指向对象的一份拷贝。