小议.NET中的对象拷贝

 

小议.NET中的对象拷贝

引言:最近准备开始写探索设计模式系列之六原型模式,希望在春节前可以写完这篇文章。为了便于阐述,在这里先对.NET中的对象拷贝机制做一些总结。——写在Post100篇之际。

概述

.NET里面,如果需要实现对象拷贝功能,那么就要实现ICloneable接口。ICloneable接口中有一个Clone方法,可以在类中覆写实现自定义的拷贝方法。对象拷贝的实现方法有两种:浅拷贝(Shallow Copy)与深拷贝(Deep Copy)。

浅拷贝与深拷贝

浅拷贝是指当对象的字段值被拷贝时,字段引用的对象不会被拷贝。例如,如果一个对象有一个指向字符串的字段,并且我们对该对象做了一个浅拷贝,那么两个对象将引用同一个字符串。而深拷贝是对对象实例中字段引用的对象也进行拷贝的一种方式,所以如果一个对象有一个指向字符串的字段,并且我们对该对象做了一个深拷贝的话,我们将创建一个新的对象和一个新的字符串--新对象将引用新字符串。需要注意的是执行深拷贝后,原来的对象和新创建的对象不会共享任何东西;改变一个对象对另外一个对象没有任何影响。(出自《.NET框架程序设计(修订版)》,李建忠译)。简单地说,浅拷贝只复制顶级(Top-Level)对象,而深拷贝则复制对象及其子对象。

示意图如下:

代码说明

下面给出浅拷贝与深拷贝的两个例子,例子使用了ICloneable接口。C#中的数组是引用型的变量,下面通过数组来进行演示:

1.浅拷贝:

using System;

namespace CopyDemo

{

    /// <summary>

    /// ShallowCopy

    /// </summary>

    public class ShallowCopy : ICloneable

    {

       public int[] s = {4,5,6,7};

 

       public Object Clone()

       {

           return this.MemberwiseClone();

       }

       public void Display()

       {

           foreach(int i in s)

           {

              Console.Write( i + ", ");

           }

           Console.WriteLine();

       }

    }

 

    class Client

    {

       public static void Main(string[] args)

       {

           ShallowCopy obj1 = new ShallowCopy();

           ShallowCopy obj2 = (ShallowCopy)obj1.Clone();

           obj1.s[0] = 1;

 

           obj1.Display();

           obj2.Display();

           Console.ReadLine();

       }

    }

}

运行结果:

1,5,6,7

1,5,6,7

ShallowCopy对象实现了一个浅拷贝,因此当对obj1进行拷贝时,其字段s并没有拷贝,这导致obj1obj2的字段s都指向了同一个s,因此,当修改了obj1s[0]后,obj2s[0]也发生了变化。

2.深拷贝:
using System;

namespace CopyDemo

{

    /// <summary>

    /// DeepCoyp

    /// </summary>

    public class DeepCopy : ICloneable

    {

        public int[] s = {4,5,6,7};

 

       // 默认构造函数

       public DeepCopy()

       {

       }

       // Clone方法调用的私有构造函数

       private DeepCopy(int[] s)

       {

           this.s = (int[])s.Clone();

       }

       public Object Clone()

       {

           // 构造一个新的DeepCopy对象

           return new DeepCopy(this.s);

       }

        public void Display()

       {

           foreach(int i in s)

           {

              Console.Write( i + ", ");

           }

           Console.WriteLine();

       }

    }

 

    class Client

    {

       public static void Main(string[] args)

       {

           DeepCopy obj1 = new DeepCopy();

           DeepCopy obj2 = (DeepCopy)obj1.Clone();

           obj1.s[0] = 1;

 

           obj1.Display();

           obj2.Display();

 

           Console.ReadLine();

       }

    }

}

运行结果:

1,5,6,7

4,5,6,7

这次在拷贝的时候,不但拷贝对象本身,连里面的数组字段一并拷贝。因此,最终打印出来的obj1dobj2不同。

总结

.NET中,由于提供了Icloneable接口,使得对象拷贝操作变得非常简单。

作者:TerryLee
出处:http://terrylee.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
posted @ 2006-01-06 17:24 TerryLee 阅读(2904) 评论(6) 编辑 收藏

 回复 引用   
#1楼 2006-01-06 22:25 msdn[未注册用户]
你写所谓深复制!只不过是在你的Colne 方法中重新new 出你的类属性的值!
当你的类中有不同有值的属性!
那请问 你这个获得整个类所有属性的值呢?
难道在 构造中写吗!

 回复 引用   
#2楼 2006-01-07 02:17 航天奇侠

也许是敏感,我觉得调用构造函数有点晕。

我更愿意直接在clone里面写出实现代码。

DeepCopy obj = new DeepCopy ();
obj.s = (int[]) this.s.Clone();

return obj;

可能是this我总认为是当前对象,而拷贝对象是新建来返回的,脑筋转不过来。

 回复 引用   
#3楼 2006-01-07 19:26 mylee[未注册用户]
~_~
 回复 引用 查看   
#4楼 2006-01-08 11:30 jkfree      
对于浅表副本拷贝可以从ICloneable来继承实现,但是深度拷贝其实可以自己写一个Copy()方法,然后直接new一个对象返回。借用上面的例子:
public class ShallowCopy : ICloneable

{

public int[] s = {4,5,6,7};



public Object Clone()

{

return this.MemberwiseClone();

}

public object Copy()
{
return new ShallowCopy();
}

public void Display()

{

foreach(int i in s)

{

Console.Write( i + ", ");

}

Console.WriteLine();

}


这样可能更是方便一点。
不要bs

现在有一个对象中有很多的属性和子对象, 请问这个对象的DeepCopy方法怎么写?谢谢!(不希望一个一个的赋值).
 回复 引用   
#6楼 2006-11-11 11:14 roogeer[匿名][未注册用户]
现在有一个对象中有很多的属性和子对象, 请问这个对象的DeepCopy方法怎么写?谢谢!(不希望一个一个的赋值).
===========================
不管有几个子对象,写法都是一样,调用每个子对象的Clone()方法, 每个'类'只关心自己的Clone()方法,子对象自己实现其Clone()方法,这样,在顶层类调用Clone()方法时,会一层一层的调用其子对象的Clone()方法.