C#複製執行個體

來源:互聯網
上載者:User

public AtmDataBase DeepClone()  {     MemoryStream ms = new MemoryStream();     BinaryFormatter bf = new BinaryFormatter();     bf.Serialize(ms, this);     ms.Position = 0;     return bf.Deserialize(ms) as AtmDataBase;  }

C# 支援兩種類型:“實值型別”和“參考型別”。

實值型別(Value Type)(如 char、int 和 float)、枚舉類型和結構類型。 參考型別(Reference Type) 包括類 (Class) 類型、介面類型、委託類型和數群組類型。

如何來劃分它們?  以它們在電腦記憶體中如何分配來劃分

實值型別與參考型別的區別? 1,實值型別的變數直接包含其資料, 2,參考型別的變數則儲存物件引用。  對於參考型別,兩個變數可能引用同一個對象,因此對一個變數的操作可能影響另一個變數所引用的對象。對於實值型別,每個變數都有自己的資料副本,對一個變數的操作不可能影響另一個變數。

 實值型別隱式繼承自System.ValueType  所以不能顯示讓一個結構繼承一個類,C#不支援多繼承

堆棧(stack)是一種先進先出的資料結構,在記憶體中,變數會被分配在堆棧上來進行操作。  堆(heap)是用於為類型執行個體(對象)分配空間的記憶體地區,在堆上建立一個對象,  會將對象的地址傳給堆棧上的變數(反過來叫變數指向此對象,或者變數引用此對象)。

關於對象複製的所設計到知識點

淺拷貝:是指將對象中的所有欄位逐字複雜到一個新對象         對實值型別欄位只是簡單的拷貝一個副本到目標對象,改變目標對象中實值型別欄位的值不會反映到原始對象中,因為拷貝的是副本         對引用型欄位則是指拷貝他的一個引用到目標對象。改變目標對象中參考型別欄位的值它將反映到原始對象中,因為拷貝的是指向堆是上的一個地址

深拷貝:深拷貝與淺拷貝不同的是對於引用欄位的處理,深拷貝將會在新對象中建立一個新的對象和         原始對象中對應欄位相同(內容相同)的欄位,也就是說這個引用和原始對象的引用是不同, 我們改變新         對象中這個欄位的時候是不會影響到原始對象中對應欄位的內容。

淺複製: 實現淺複製需要使用Object類的MemberwiseClone方法用於建立一個淺表副本  深複製: 須實現 ICloneable介面中的Clone方法,且需要需要複製的對象加上[Serializable]特性

class DrawBase : System.Object, ICloneable     {        

  public string name = "jmj";        

   public DrawBase()         {         }

      public object Clone()         {            

       return this as object;      //引用同一個對象            

       return this.MemberwiseClone(); //淺複製            

       return new DrawBase() as object;//深複製        

   }    

}    

class Program     {

        static void Main(string[] args)         {  

           DrawBase rect = new DrawBase();            

    Console.WriteLine(rect.name);            

    DrawBase line = rect.Clone() as DrawBase;            

    line.name = "a9fs3";            

    Console.WriteLine(rect.name);            

    DrawBase ploy = line.Clone() as DrawBase;            

    ploy.name = "lj";            

    Console.WriteLine(rect.name);

           Console.WriteLine(object.ReferenceEquals(line, ploy));            

    Console.ReadLine();        

  }    

}

運行結果:  return this as object;      //引用同一個對象  

輸出:jmj          a9fs3          lj          True    

return this.MemberwiseClone(); //淺複製

return new DrawBase() as object;//深複製

輸出均為: jmj               jmj               jmj               False

解釋: return this as object 方法總是引用同一個對象,因此相應的堆記憶體上的值會改變!  後兩種方法都是對對象的複製,區別在於複製的類別不同:深複製會複製整個填充的對象,包括該對象中其他參考型別和實值型別的值;而淺複製只複製了一個對象中所有引用,它沒有值的複製,通過引用它們的其他對象的引用來共用它們。

 --------------------------------------------------------------------------------------------------------

 

雖然在現實世界中的複製課題是有爭議的, 在.NET世界使用它卻足夠安全, 難道不是嗎?

 

為實現一個類你究竟有多少次要實現ICloneable介面, 而且每一次都寫相同的代碼,或為每個類寫特定的代碼。

而且,當你的類加入一個新的欄位時,往往會忘記更新這個新欄位的複製方法。如果我沒說錯的話,這種時候往往會帶來惱人的bugs。

 

這是我的類得以存在的原因。 藉由反射機制的小小協助,我建立了一個用預設行為實現了ICloneable介面的抽象類別。

現在或許你正在問自己: 什麼是預設行為? 那麼我很高興你這樣詢問。 複製的預設行為,是採用以下的規則來複製類中的每一個欄位:

 

查看一下類中的每一個欄位是否支援ICloneable介面

如果某欄位不支援ICloneable介面,那麼該欄位將以常規方式處理。

這意味著,如果該欄位是一個實值型別,那麼該值被拷貝;如果該欄位是一個參考型別,複製的欄位將指向同一個對象。

如果該欄位支援ICloneable介面,我們將使用其本身的Clone方法對其進行複製。

如果該欄位支援IEnumerable介面,我們需要檢查他是否支援IList 或 IDictionary 介面。

如果支援,那麼我們迭代該集件,並且查看集合的每一項是否支援ICloneable介面。

如何使用

讓你的類支援Icloneable介面所要做的就是,將你的類繼承自如下所述的BaseObject類:

 

public class MyClass : BaseObject

{

    public string myStr =”test”;

    public int id;

}

public class MyContainer : BaseObject

{   

public string name = “test2”;

public MyClass[] myArray= new MyClass[5];    

public class MyContainer()   

{       

for(int i=0 ; i<5 ; i++)       

{            

this.myArray[I] = new MyClass();       

}   

}

}

 

現在在Main方法中加入如下代碼:

 

static void Main(string[] args){

    MyContainer con1 = new MyContainer();   

MyContainer con2 = (MyContainer)con1.Clone();   

con2.myArray[0].id = 5;

}

當監測con2執行個體時,你將會看到MyClass執行個體的第一項已經變為5,而con1執行個體卻沒有改變。

這樣你將明白加入到類中的任意支援ICloneable介面的欄位將被同樣地複製。

而且,如果該欄位支援IList 或 IDictionary 介面,複製方法將偵測該欄位,輪詢所有項,並同樣地試圖對他們進行複製。

  實現

/// <summary>
    /// BaseObject類是一個用來繼承的抽象類別。
    /// 每一個由此類繼承而來的類將自動支援複製方法。
    /// 該類實現了Icloneable介面,並且每個從該對象繼承而來的對象都將同樣地
    /// 支援Icloneable介面。
    /// </summary>
    public abstract class BaseObject : ICloneable
    {
        /// <summary>   
        /// 複製對象,並返回一個已複製對象的引用   
        /// </summary>   
        /// <returns>引用新的複製對象</returns>    
        public object Clone()
        {
            //首先我們建立指定類型的一個執行個體        
            object newObject = Activator.CreateInstance(this.GetType());
            //我們取得新的類型執行個體的欄位數組。        
            FieldInfo[] fields = newObject.GetType().GetFields();
            int i = 0;
            foreach (FieldInfo fi in this.GetType().GetFields())
            {
                //我們判斷欄位是否支援ICloneable介面。            
                Type ICloneType = fi.FieldType.
                 GetInterface("ICloneable", true);
                if (ICloneType != null)
                {
                    //取得對象的Icloneable介面。                
                    ICloneable IClone = (ICloneable)fi.GetValue(this);
                    //我們使用複製方法給欄位設定新值。               
                    fields[i].SetValue(newObject, IClone.Clone());
                }
                else
                {
                    // 如果該欄位部支援Icloneable介面,直接設定即可。                
                    fields[i].SetValue(newObject, fi.GetValue(this));
                }
                //現在我們檢查該對象是否支援IEnumerable介面,如果支援,            
                //我們還需要枚舉其所有項並檢查他們是否支援IList 或 IDictionary 介面。           
                Type IEnumerableType = fi.FieldType.GetInterface("IEnumerable", true);
                if (IEnumerableType != null)
                {
                    //取得該欄位的IEnumerable介面               
                    IEnumerable IEnum = (IEnumerable)fi.GetValue(this);
                    //這個版本支援IList 或 IDictionary 介面來迭代集合。               
                    Type IListType = fields[i].FieldType.GetInterface("IList", true);
                    Type IDicType = fields[i].FieldType.GetInterface("IDictionary", true);
                    int j = 0;
                    if (IListType != null)
                    {
                        //取得IList介面。                    
                        IList list = (IList)fields[i].GetValue(newObject);
                        foreach (object obj in IEnum)
                        {
                            //查看當前項是否支援支援ICloneable 介面。                        
                            ICloneType = obj.GetType().
                             GetInterface("ICloneable", true);
                            if (ICloneType != null)
                            {
                                //如果支援ICloneable 介面,   
                                //我們用它李設定列表中的對象的複製   
                                ICloneable clone = (ICloneable)obj;
                                list[j] = clone.Clone();
                            }
                            //注意:如果列表中的項不支援ICloneable介面,那麼                     
                            //在複製列表的項將與原列表對應項相同                     
                            //(只要該類型是參考型別)                       
                            j++;
                        }
                    }
                    else if (IDicType != null)
                    {
                        //取得IDictionary 介面                   
                        IDictionary dic = (IDictionary)fields[i].
                         GetValue(newObject);
                        j = 0;
                        foreach (DictionaryEntry de in IEnum)
                        {
                            //查看當前項是否支援支援ICloneable 介面。                        
                            ICloneType = de.Value.GetType().
                             GetInterface("ICloneable", true);
                            if (ICloneType != null)
                            {
                                ICloneable clone = (ICloneable)de.Value;
                                dic[de.Key] = clone.Clone();
                            }
                            j++;
                        }
                    }
                }
                i++;
            }
            return newObject;
        }
    }

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.