浅复制(Shallow Copy)与深复制(Deep Copy)

复制:对象的复制是生成一个与指定对象完全一样的新对象,实现的方式根据定义可以知道,新建一个类型相同的对象,然后复制原对象的每一个成员和字段。

 浅复制:

    class Program
    {
        static void Main(string[] args)
        {
            ClassA A = new ClassA();
            CloneObj clone = new CloneObj();
            ClassA newA= clone.CloneA(A);
        }
    }

    public class ClassA
    {
        public Int32 AValue = 100;
    }

    public class ClassB
    {
        public Int32 BValue = 200;
    }

    public class CloneObj
    {
        public ClassA CloneA(ClassA obj)
        {
            ClassA newAobj = new ClassA();
            newAobj.AValue = obj.AValue;
            return newAobj;
        }
    }

上面的CloneObj的CloneA方法就是一个浅复制ClassA对象,修改代码:

    class Program
    {
        static void Main(string[] args)
        {
            ClassA A = new ClassA();
            CloneObj clone = new CloneObj();
            ClassA newA= clone.CloneA(A);
        }
    }

    public class ClassA
    {
        public Int32 AValue = 100;
        public ClassB objB;
        public ClassA()
        {
            objB = new ClassB();
        }
    }

    public class ClassB
    {
        public Int32 BValue = 200;
    }

    public class CloneObj
    {
        public ClassA CloneA(ClassA obj)
        {
            ClassA newAobj = new ClassA();
            newAobj.AValue = obj.AValue;
            newAobj.objB = obj.objB;
            return newAobj;
        }
    }

这里ClassA里面包含了引用类型的ClassB对象,这里复制的ClassA对象,如下图:

上面这种方式就是“浅复制(Shallow Copy)”,这里可以在调试时测试下,看看A里面objB的地址和通过复制方法出来的newA的objB的地址:

地址完全一样

浅复制是.NET默认的对象复制方式,Object类提供的Memberwise方法浅复制一个对象。实现深复制,也就是上面的图中,不是共用一个ClassB对象,而是完全创建一个新的ClassB对象。这需要实现ICloneable接口.如下:

namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            ClassA A = new ClassA();
            CloneObj clone=new CloneObj();
            ClassA newA = clone.CloneA(A);

        }
    }

    public class ClassA:ICloneable
    {
        public Int32 AValue = 100;
        public ClassB objB;
        public ClassA()
        {
            objB = new ClassB();
        }

        object ICloneable.Clone()
        {
            ClassA objA = new ClassA();
            objA.AValue = this.AValue;
            objA.objB = (this.objB as ICloneable).Clone() as ClassB;
            return objA;
        }
    }

    public class ClassB:ICloneable
    {
        public Int32 BValue = 200;

        object ICloneable.Clone()
        {
            ClassB objB = new ClassB();
            objB.BValue = this.BValue;
            return objB;
        }
    }

    public class CloneObj
    {
        public ClassA CloneA(ClassA obj)
        {
            //ClassA newAobj = new ClassA();
            //newAobj.AValue = obj.AValue;
            //newAobj.objB = obj.objB;
            ClassA newAobj = (obj as ICloneable).Clone() as ClassA;
            return newAobj;
        }
    }

}

测试结果如图:

这里完成了深复制

对象序列化

对象复制比较简单的方式是序列化,将类标记为[Serializable]。对象序列化主要解决的是对象状态的保存问题,这里所说的“对象状态”是指某一时刻对象拥有的字段值的集合。

对象的序列化:将一个内存的对象保存到流中,并在需要时从流中读取数据重建对象的过程称为“对象序列化”和“反序列化”

流:代表一连串有顺序的二进制数据。

利用序列化进行对象的复制——深复制

    [Serializable]
    class MyClass
    {
        public int Index = 1;
    }

    class Program
    {
        static void Main(string[] args)
        {
            MyClass obj = new MyClass();
            //创建一个内存流对象
            using (MemoryStream ms = new MemoryStream())
            {
                IFormatter formator = new BinaryFormatter();
                formator.Serialize(ms, obj);  //将对象序列化到内存流中 

                //克隆100个对象
                for (int i = 0; i < 100; i++)
                {
                    ms.Seek(0, SeekOrigin.Begin);//回到流的开头
                    obj = (formator.Deserialize(ms) as MyClass); //反序列化对象
                    obj.Index += i;   //设置对象字段
                    Console.WriteLine("对象{0}已创建。", obj.Index);
                }
            }
            Console.ReadKey();
        }
    }

原理是将对象序列化到流中,然后从流中创建对象(批量),从而实现了深复制。

读书笔记《.NET4.0面向对象编程漫谈》作者:金旭亮老师

posted @ 2013-01-24 15:17 Rt-张雪飞 阅读(...) 评论(...) 编辑 收藏