• C# 浅拷贝和深拷贝


    本文主要通过事例分析引用类型的浅拷贝和深拷贝之间的区别,

    还是从代码开始吧:

    一、浅拷贝:

    声明一个将要被克隆的类 clsShallow 和它将要包含的引用类型成员clsRefSalary类clsShallow包含 CompanyName(静态字符串)、Age(值类型)、EmployeeName(字符串)、EmpSalary(引用类型)四个成员。

    public class clsShallow
        {
            public static string CompanyName = "My Company";
            public int Age;
            public string EmployeeName;
            public clsRefSalary EmpSalary;
    
            public clsShallow CreateShallowCopy(clsShallow inputcls)
            {
                return (clsShallow)inputcls.MemberwiseClone();
            }
        }
        public class clsRefSalary
        {
            public clsRefSalary(int _salary)
            {
                Salary = _salary;
            }
            public int Salary;
        }

    再看如何调用:

     static void Main()
        {
            // Creates an instance of clsShallow and assign values to its fields.
            clsShallow objshallow = new clsShallow();
            objshallow.Age = 25;
            objshallow.EmployeeName = "Ahmed Eid";
            // add the ref value to the objshallow 
            clsRefSalary clsref = new clsRefSalary(1000);
            objshallow.EmpSalary = clsref;
    
            // Performs a shallow copy of m1 and assign it to m2.
            clsShallow m2 = objshallow.CreateShallowCopy(objshallow);
            m2.Age = 20;
            m2.EmployeeName = "jay";
    
            // then modify the clsref salary value to be 2000
            clsref.Salary = 2000;
            // so the m1 object salary value become 2000
    
            Console.WriteLine(m2 == objshallow);
            Console.WriteLine(objshallow.EmpSalary.Salary);
            Console.WriteLine(m2.EmpSalary.Salary);
            Console.WriteLine(objshallow.Age);
            Console.WriteLine(m2.Age);
            Console.WriteLine(objshallow.EmployeeName);
            Console.WriteLine(m2.EmployeeName);
        }

    最后看运行结果:

    根据结果我们进行分析:

    浅拷贝:

    1、浅拷贝创建了类的一个新实例。(由对象的同一性得知:如果两个引用如m2 、 objshallow指向同一个对象的实例,则(m2 == objshallow)为true,而结果显示为  false,所以m2 和objshallow分别指向不同的实例,而objshallow引用所指向的实例是新创建的。

    2、对于对象(clsShallow)中的引用类型成员(clsRefSalary),引用被复制,但引用的实例没有被复制,即新创建实例中的引用成员(m2.EmpSalary)等于原实例的引用成员(objshallow.EmpSalary)。 因为改变 clsref.Salary 等于2000后,objshallow.EmpSalary 和m2.EmpSalary的Salary都改变了。其实可通过Console.WriteLine(objshallow.EmpSalary == m2.EmpSalary) 输出为true来解释。

    3、值类型字段逐位复制到新实例。即改变m2.Age不影响objshallow.Age值。有人要问,string 为引用类型,为什么改变m2.EmployeeName = "jay"而objshallow.EmployeeName = "Ahmed Eid"没变呢?这是因为:字符串具有恒等性,一个字符串一旦被创建,我们就不能再将其变长、变短、或者改变其中的任何字符。

    二、 深拷贝:

    修改代码如下:

    static void Main()
        {
            clsDeep objdeep = new clsDeep();
            objdeep.Age = 25;
            objdeep.EmployeeName = "Ahmed Eid";
    
            // add the ref value
            clsRefSalary clsref = new clsRefSalary(1000);
            objdeep.EmpSalary = clsref;
    
            // Performs a shallow copy of m1 and assign it to m2.
            clsDeep m2 = objdeep.CreateDeepCopy(objdeep);
    
            // then modify the clsref salary value to be 2000 
            clsref.Salary = 2000;
    
            // so the m1 object salary value become 2000
            int EmpSalary = objdeep.EmpSalary.Salary;
            m2.Age = 20;
            m2.EmployeeName = "jay";
    
            // then modify the clsref salary value to be 2000
            clsref.Salary = 2000;
            // so the m1 object salary value become 2000
            Console.WriteLine(m2 == objdeep);
            Console.WriteLine(objdeep.EmpSalary.Salary);
            Console.WriteLine(m2.EmpSalary.Salary);
            Console.WriteLine(objdeep.EmpSalary == m2.EmpSalary);
            Console.WriteLine(objdeep.Age);
            Console.WriteLine(m2.Age);
            Console.WriteLine(objdeep.EmployeeName);
            Console.WriteLine(m2.EmployeeName);
        }
    
    
        [Serializable]
        // serialize the classes in case of deep copy
        public class clsDeep
        {
            public static string CompanyName = "My Company";
            public int Age;
            public string EmployeeName;
            public clsRefSalary EmpSalary;
            public clsDeep CreateDeepCopy(clsDeep inputcls)
            {
                MemoryStream m = new MemoryStream();
                BinaryFormatter b = new BinaryFormatter();
                b.Serialize(m, inputcls);
                m.Position = 0;
                return (clsDeep)b.Deserialize(m);
            }
        }
    
        [Serializable]
        public class clsRefSalary
        {
            public clsRefSalary(int _salary)
            {
                Salary = _salary;
            }
            public int Salary;
        }

    记得加命名空间

    using System.IO;
    using System.Runtime.Serialization.Formatters.Binary;

     查看结果:

     深拷贝:

    1、深拷贝创建了类的一个新实例

    2、对于实例中的引用类型成员,创建引用类型成员对象的新副本。 ( objshallow.EmpSalary != m2.EmpSalary)

    3、值类型字段逐位复制到新实例

    实,浅拷贝和深拷贝的本质区别是实例中的引用类型成员如何拷贝, 浅拷贝复制引用,深拷贝创建新实例。

    注:无论浅、深拷贝,静态成员都不会复制,因为静态成员属于类成员。

    三 、深复制方法

    /// <summary> 
            /// Perform a deep Copy of the object. 
            /// </summary> 
            /// <typeparam name="T">The type of object being copied.</typeparam> 
            /// <param name="source">The object instance to copy.</param> 
            /// <returns>The copied object.</returns> 
            public static T Clone<T>(this T source) 
            {
                if (!typeof(T).IsSerializable)
                {
                    throw new ArgumentException("The type must be serializable.", "source");
                }
    
                // Don't serialize a null object, simply return the default for that object 
                if (Object.ReferenceEquals(source, null))
                {
                    return default(T);
                }
    
                IFormatter formatter = new BinaryFormatter();
                Stream stream = new MemoryStream();
                using (stream)
                {
                    formatter.Serialize(stream, source);
                    stream.Seek(0, SeekOrigin.Begin);
                    return (T)formatter.Deserialize(stream);
                }
            }

    摘自:http://www.codeproject.com/Articles/28952/Shallow-Copy-vs-Deep-Copy-in-NET

  • 相关阅读:
    怎么看待MYSQL的性能
    java dom4j 读写XML
    cas4.2的安装
    java websocket
    解决openresty http客户端不支持https的问题
    开源许可证GPL、BSD、MIT、Mozilla、Apache和LGPL的区别
    SpringMVC框架的学习(一):初步认识
    Spring框架: 理解为它是一个管理对象的创建,依赖,销毁的容器。
    Springmvc如何进行异常处理
    Springmvc:注解有哪些。
  • 原文地址:https://www.cnblogs.com/zhangzhi19861216/p/2750290.html
Copyright © 2020-2023  润新知