zoukankan      html  css  js  c++  java
  • 深层拷贝和浅层拷贝

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

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

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

  • 相关阅读:
    PHP调试的时候出现了警告:
    快报滚动
    js foreach、map函数
    箭头函数和普通函数的区别
    flex布局
    react+propTypes
    手机尺寸
    less的使用
    发现是在IE6-IE9下,下列元素table,thead,tfoot,tbody,tr,col,colgroup,html,title,style,frameset的innerHTML属性是只读的
    div+css 组织结构
  • 原文地址:https://www.cnblogs.com/lusunqing/p/3243145.html
Copyright © 2011-2022 走看看