对C#对象的Shallow、Deep Cloning认识

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

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

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

对C#对象的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();

        }

    }
复制代码

 

运行结果是:

对C#对象的Shallow、Deep Cloning认识

 

接下来思考一下吧,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

你可能感兴趣的:(sha)