文章出處

好像園內比較多博客對 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


文章列表




Avast logo

Avast 防毒軟體已檢查此封電子郵件的病毒。
www.avast.com


arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()