深复制VS浅复制(MemberwiseClone方法详解)

  MemberwiseClone方法,属于命名空间System,存在于程序集 mscorlib.dll中。返回值是System.Object。其含义是:创建一个当前object对象的浅表副本。

MSDN中的官方解释是:

  MemberwiseClone 方法创建一个浅表副本,方法是创建一个新对象,然后将当前对象的非静态字段复制到该新对象。如果字段是值类型的,则对该字段执行逐位复制。如果字段是引用类型,则复制引用但不复制引用的对象;因此,原始对象及其复本引用同一对象。

  例如:考虑引用对象 A 和 B 的被称为 X 的对象。对象 B 依次引用对象 C。X 的浅表副本创建一个新对象 X2,该对象也引用对象 A 和 B。相比而言,X 的深层副本创建一个新对象 X2,该对象引用新对象 A2 和 B2(分别为 A 和 B 的副本)。B2 又引用新对象 C2,C2 是 C 的副本。该示例阐释了浅层和深层复制操作之间的区别。

有很多方法可以实现深层复制操作,前提是浅表复制操作由MemberwiseClone 方法执行但不符合您的需求。这些要求包括:  

   1、调用要复制的对象的类构造函数以创建含有从第一个对象中提出的属性值的第二个对象。这假定对象的值完全由类构造函数定义。

   2、调用MemberwiseClone 方法创建的对象的浅表副本,然后将指定新的对象,其值均相同,原始对象的任何属性或字段的值是引用类型。该示例中的DeepCopy 方法阐释了这种方法。

   3、序列化要深层复制的对象,然后将序列化的数据还原到另一个对象变量。

   4、 使用带递归的反射执行的深层复制操作。

估计看到这你早就已经是晕的不行了吧!呵呵,本菜鸟也是这样滴……在自己的不懈努力之下,并且从实例中试验过后才弄明白,原来这个所谓的浅复制和深复制是如此的简单啊!

  其实,用咱们在windows操作系统中使用的快捷方式和源文件的关系来理解就简单了!相信大家从玩电脑开始可能都遇到过这样的尴尬局面,就是用u盘复制了电脑的文件,然后兴高采烈的去打印,然后一到打印店打开u盘中复制到的文件,“纳尼!怎么打不开呢!原来是自己复制了一个快捷方式,额&……”(哈哈……说到这,估计有的人就非常有共鸣了啦!是吧?)

  快捷方式:其实就相当于是引用源文件,快捷方式中并不存在源文件对象,只是存放了一个源文件的地址,这个地址指向源文件,当你双击的时候,windows会根据这个地址去你的电脑寻找这个源文件并打开。只复制一个快捷方式,这就相当于是浅复制啦

  复制源文件:将文件的数据都复制过来,这就是所谓的深复制。

还不懂?看一个实例吧!(灵感来自:大话设计模式之原型模式——简历复制)

  先看类图:



浅复制:

  客户端代码如下

            Resume Rbill = new Resume("bill");
            Rbill.SetPersonalInfo("man", "11");
            Rbill.SetWorkExperience("2015-1-2-2015-12-10", "IBM");

            Resume Rcindy = (Resume)Rbill.Clone();      
            Rcindy.SetWorkExperience("2015-1-2至2015-11-11", "Microsoft");

            Resume Rll = (Resume)Rbill.Clone();
            Rll.SetPersonalInfo("rll", "99");
            Rll.SetWorkExperience("2015-1-2至2015-11-11", "甲骨文");
           
            Rbill.Display();
            Rcindy.Display();
            Rll.Display();
            Console.Read();
    类的代码如下:

 public class Resume : ICloneable
    {
        private string name;
        private string age;
        private string sex;
        //private string workDate;
       // private string company;
        private Workexperience work;
        public Resume(string strName)
        {
            this.name = strName;
            work = new Workexperience();        //在初始化Resume的同时实例化一个Workexperience对象。
        }

        //提供clone 方法调用的私有构造函数,以便克隆数据。
        private Resume(Workexperience work)
        {
            this.work = (Workexperience)work.Clone();
        }
        public void SetPersonalInfo(string sex, string age)
        {
            this.sex = sex;
            this.age = age;
        }

        public void SetWorkExperience(string workDate, string company)
        {
            work.WorkDate  = workDate;
            work.Company  = company;

        }

        public void Display()
        {
            Console.WriteLine("{0},{1},{2}", name, sex, age);
            Console.WriteLine("{0},{1}", work .WorkDate , work.Company );   // 引用work类的属性、字段。

        }

        public object Clone()
        {
            Resume obj = new Resume(this.work);  //调用私有构造函数,完成克隆,并给简历对象的相关字段赋值,返回深复制简历对象
            obj.name = name;
            obj.sex = sex;
            //obj.workDate = workDate;
            obj.age = age;
            return obj;
            //return (object)this.MemberwiseClone();


        }
    }
    class Workexperience : ICloneable
    {
        private string workDate;
        private string company;

        public string WorkDate
        {
            get { return workDate; }
            set { workDate = value; }
        }
        public string Company
        {
            get { return company; }
            set { company = value; }
        }

        public object Clone()
        {
            return (object)this.MemberwiseClone();
        }
    }

  看到这里,有没有豁然开朗的赶脚呢?

  ok,that's it! thank you for your attention!


  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 30
    评论
C#的序列化和反序列化是将对象转换为二进制数据或将二进制数据转换为对象的过程。在C#中,可以使用BinaryFormatter、XmlSerializer、DataContractSerializer等多种方式进行序列化和反序列化。 拷贝和拷贝用于复制对象。拷贝只复制对象的引用,而不会复制对象的实际内容。拷贝则会完全复制对象的内容,包括引用类型的成员变量。 在C#中,可以通过实现ICloneable接口来实现拷贝。对于拷贝,则需要自己手动实现一个递归复制对象的方法。 下面是一个示例代码,演示了如何进行序列化、反序列化以及拷贝和拷贝: ```csharp using System; using System.IO; using System.Runtime.Serialization.Formatters.Binary; using System.Xml.Serialization; [Serializable] public class Person : ICloneable { public string Name { get; set; } public int Age { get; set; } public Address Address { get; set; } public object Clone() { return new Person { Name = Name, Age = Age, Address = (Address)Address?.Clone() }; } } [Serializable] public class Address : ICloneable { public string City { get; set; } public string Street { get; set; } public object Clone() { return new Address { City = City, Street = Street }; } } public static class SerializationHelper { public static byte[] SerializeToBinary(object obj) { using (var ms = new MemoryStream()) { var formatter = new BinaryFormatter(); formatter.Serialize(ms, obj); return ms.ToArray(); } } public static T DeserializeFromBinary<T>(byte[] data) { using (var ms = new MemoryStream(data)) { var formatter = new BinaryFormatter(); return (T)formatter.Deserialize(ms); } } public static string SerializeToXml(object obj) { using (var writer = new StringWriter()) { var serializer = new XmlSerializer(obj.GetType()); serializer.Serialize(writer, obj); return writer.ToString(); } } public static T DeserializeFromXml<T>(string xml) { using (var reader = new StringReader(xml)) { var serializer = new XmlSerializer(typeof(T)); return (T)serializer.Deserialize(reader); } } } public static class ObjectHelper { public static T ShallowCopy<T>(this T obj) { return (T)obj.MemberwiseClone(); } public static T DeepCopy<T>(this T obj) { using (var ms = new MemoryStream()) { var formatter = new BinaryFormatter(); formatter.Serialize(ms, obj); ms.Position = 0; return (T)formatter.Deserialize(ms); } } } // 示例代码 var person1 = new Person { Name = "Tom", Age = 30, Address = new Address { City = "Beijing", Street = "Chang'an Avenue" } }; // 拷贝 var person2 = person1.DeepCopy(); person2.Name = "Jerry"; person2.Address.City = "Shanghai"; Console.WriteLine($"person1.Name={person1.Name}, person1.Address.City={person1.Address.City}"); Console.WriteLine($"person2.Name={person2.Name}, person2.Address.City={person2.Address.City}"); // 拷贝 var person3 = person1.ShallowCopy(); person3.Name = "John"; person3.Address.City = "Guangzhou"; Console.WriteLine($"person1.Name={person1.Name}, person1.Address.City={person1.Address.City}"); Console.WriteLine($"person3.Name={person3.Name}, person3.Address.City={person3.Address.City}"); // 序列化和反序列化 var data = SerializationHelper.SerializeToBinary(person1); var person4 = SerializationHelper.DeserializeFromBinary<Person>(data); Console.WriteLine($"person1.Name={person1.Name}, person1.Address.City={person1.Address.City}"); Console.WriteLine($"person4.Name={person4.Name}, person4.Address.City={person4.Address.City}"); var xml = SerializationHelper.SerializeToXml(person1); var person5 = SerializationHelper.DeserializeFromXml<Person>(xml); Console.WriteLine($"person1.Name={person1.Name}, person1.Address.City={person1.Address.City}"); Console.WriteLine($"person5.Name={person5.Name}, person5.Address.City={person5.Address.City}"); ``` 输出结果: ``` person1.Name=Tom, person1.Address.City=Beijing person2.Name=Jerry, person2.Address.City=Shanghai person1.Name=Tom, person1.Address.City=Guangzhou person3.Name=John, person3.Address.City=Guangzhou person1.Name=Tom, person1.Address.City=Beijing person4.Name=Tom, person4.Address.City=Beijing person1.Name=Tom, person1.Address.City=Beijing person5.Name=Tom, person5.Address.City=Beijing ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 30
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值