对C#对象的Shallow、Deep Cloning认识【转】

好像园内比较多博客对 Shallow、Deep Cloning的翻译是深拷贝、浅拷贝,当时我懵了,这个叫法怎么怪怪的。

就好像看军情观察室,台湾评论员,导弹叫飞弹。

至于它们的区别,一张图就可以解释。

这两个概念,经常对一些对象操作时,忘了自己使用的是shallow 还是deep,而搞到神经大条。

  MSDN的解释是:

  Clone can be implemented either as a deep copy or a shallow copy.In a deep copy, all objects are duplicated; whereas, in a shallow copy, only the top-level objects are duplicated and the lower levels contain references.http://msdn.microsoft.com/zh-cn/library/system.icloneable.clone.aspx

  Shallow copy by creating a new object, and then copying the nonstatic fields of the current object to the new object.If a field is a value type, a bit-by-bit copy of the field is performed.If a field is a reference type, the reference is copied but the referred object is not; therefore, the original object and its clone refer to the same object.http://msdn.microsoft.com/zh-cn/library/system.object.memberwiseclone.aspx

先说一下string,因为测试代码用了string对象:

string testClone = "a测试";
 testClone = "b测试";
 Console.WriteLine("testClone:" + testClone);

 

复制代码
.entrypoint
  // 代码大小       37 (0x25)
  .maxstack  2
  .locals init ([0] string testClone)
  IL_0000:  nop
  IL_0001:  ldstr      bytearray (61 00 4B 6D D5 8B )                               // a.Km..
  IL_0006:  stloc.0
  IL_0007:  ldstr      bytearray (62 00 4B 6D D5 8B )                               // b.Km..
  IL_000c:  stloc.0
  IL_000d:  ldstr      bytearray (74 00 65 00 73 00 74 00 43 00 6C 00 6F 00 6E 00   // t.e.s.t.C.l.o.n.
                                  65 00 1A FF )                                     // e...
  IL_0012:  ldloc.0
  IL_0013:  call       string [mscorlib]System.String::Concat(string,
                                                              string)
  IL_0018:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_001d:  nop
  IL_001e:  call       int32 [mscorlib]System.Console::Read()
  IL_0023:  pop
  IL_0024:  ret
复制代码

 

testClone = "b测试";创建了"b测试"对象,并将该对象指引赋值给 testClone;

String 对象称为不可变的(只读),因为一旦创建了该对象,就不能修改该对象的值。看来似乎修改了 String 对象的方法实际上是返回一个包含修改内容的新 String 对象。如果需要修改字符串对象的实际内容,请使用 System.Text.StringBuilder 类。

想查看IL指令,请看中英文对照表:

CN-http://www.cnblogs.com/flyingbirds123/archive/2011/01/29/1947626.html;

ES-http://en.csharp-online.net/CIL_Instruction_Set.

下面是我的测试代码:

复制代码
CouponConfig couponClone = new CouponConfig() { Amount = 10, CouponName = "测试1", ListTest = new List<string> { "a", "b" } };
            CouponConfig coupon1Clone = couponClone;
            CouponConfig coupon2Clone = (CouponConfig)couponClone.Clone();
            CouponConfig coupon3Clone = null;

            using (Stream objectStream = new MemoryStream())
            {
                IFormatter formatter = new BinaryFormatter();
                formatter.Serialize(objectStream, couponClone);
                objectStream.Seek(0, SeekOrigin.Begin);
                coupon3Clone = (CouponConfig)formatter.Deserialize(objectStream);
            }
            couponClone.CouponName = "测试2";
            coupon2Clone.ListTest.Add("c");
            coupon3Clone.ListTest.Add("d");

            Console.WriteLine("couponClone:" + couponClone.CouponName);
            Console.WriteLine("coupon2Clone:" + coupon2Clone.CouponName);
            foreach (string c in couponClone.ListTest)
            {
                Console.Write(c);
            }
            Console.WriteLine("");
            foreach (string c in coupon2Clone.ListTest)
            {
                Console.Write(c);
            }
            Console.WriteLine("");
            foreach (string c in coupon3Clone.ListTest)
            {
                Console.Write(c);
            }
            Console.WriteLine("");
            Console.Read();
复制代码

 

复制代码
[Serializable]
    public class CouponConfig : ICloneable
    {

        private CouponConfig config;
        public CouponConfig Config
        {
            get
            {
                if (config == null)
                {
                    config = null;
                }
                return config;
            }
        }

        public CouponConfig()
        { }
        #region Model
        private int _amount;
        private string _couponname;
        private List<string> listTest;
        public string CouponName
        {
            get { return _couponname; }
            set { _couponname = value; }
        }
        public List<string> ListTest
        {
            get { return listTest; }
            set { listTest = value; }
        }
        public int Amount
        {
            set { _amount = value; }
            get { return _amount; }
        }

        #endregion Model

        public object Clone()
        {
            return this.MemberwiseClone();
        }
    }
复制代码

 

运行结果是:

 

接下来思考一下吧,datatable的Copy、Clone是什么cloning呢?

DataTable dt = new DataTable();
DataTable dtcopy = dt.Copy();
DataTable dtclone = dt.Clone();

 

当然最常见的是Ling to sql 的操作,where、OrderBy···,是什么cloning呢?

对象类实现了ICloneable就可以使用this.MemberwiseClone(); 实现shallow cloning;

也可以自己写clone

public class Person : ICloneable
{
    public string Name;
    public Person Spouse;
    public object Clone()
    {
        Person p = new Person();
        p.Name = this.Name;
        if (this.Spouse != null)
            p.Spouse = (Person)this.Spouse.Clone();
        return p;
    }
}

Deep Cloning可以使用 Serialization

复制代码
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
 public static class ObjectCopier
{
    /// <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>(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.cnblogs.com/daihuiquan/archive/2013/02/14/2910657.html

posted @ 2013-07-20 23:15  stu_acer  阅读(460)  评论(0编辑  收藏  举报