深复制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
    评论
评论 30
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值