程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 話談c#拷貝

話談c#拷貝

編輯:C#入門知識

 c#中類型分為值類型和引用類型,值類型對象賦值是本身就是賦的自身的一個副本,而引用類型賦值時則賦的是指向堆上的內存,假如我們不想賦這個地址而想將對象賦過去要怎麼做呢?首先要知道拷貝分為淺表拷貝和深層拷貝,淺表拷貝得到一個新的實例,一個與原始對象類型相同、值類型字段相同的拷貝。但是,如果字段是引用類型的,則拷貝的是該引用, 而不是的對象。若想將引用字段的對象也拷貝過去,則稱為深拷貝。 為了實現拷貝,本文總結了以下幾種方法。   1.首先就是最笨的方法,傳說中的“人工拷貝”,就是將引用裡的所有值對象和具有值特征的string對象一一賦給新對象,這種方式代碼量過大而且維護起來相當麻煩,所以能不用就不用。   2.System.Object提供了受保護的方法 MemberwiseClone,可用來實現“淺表”拷貝。由於該方法標記為“受保護”級別,因此,我們只能在繼承類或該類內部才能訪問該方法。   復制代碼  public class A     {         public string rr { get; set; }         public string tt { get; set; }             public A ShallowCopy()         {             return (A)this.MemberwiseClone();         }       } 復制代碼 3.使用序列化與反序列化的方式,這種方式雖可實現深度拷貝,但有點大炮打蚊子的味道,而且在外面引用時一定要記得關閉所創建的MemoryStream流   復制代碼  public static object Clone(object o,out MemoryStream ms)         {             BinaryFormatter bf = new BinaryFormatter();                         ms = new MemoryStream();             bf.Serialize(ms,o);             ms.Seek(0, SeekOrigin.Begin);               return bf.Deserialize(ms);         } 復制代碼 4.在一個外國人寫的博客中(http://www.codeproject.com/Articles/3441/Base-class-for-cloning-an-object-in-C),使用反射的方法來解決了這個問題。他寫了一個BaseObject類,如果我們繼承這個類就可以實現深度拷貝,下面是他的實現方法:   創建一個實現 ICloneable 接口的有默認行為的抽象類,所謂的默認行為就是使用以下庫函數來拷貝類裡的每一個字段。   1.遍歷類裡的每個字段,看看是否支持ICloneable接口。   2.如果不支持ICloneable接口,按下面規則進行設置,也就是說如果字段是個值類型,那將其拷貝,如果是引用類型則拷貝字段指向通一個對象。   3.如果支持ICloneable,在科隆對象中使用它的克隆方法進行設置。   4.如果字段支持IEnumerable接口,需要看看它是否支持IList或者IDirectionary接口,如果支持,迭代集合看看是否支持ICloneable接口。   我們所要做的就是使得所有字段支持ICloneable接口。   下面是測試結果:   復制代碼 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();         }     } } 復制代碼 復制代碼 static void Main(string[] args) {     MyContainer con1 = new MyContainer();     MyContainer con2 = (MyContainer)con1.Clone();      con2.myArray[0].id = 5; } 復制代碼 con2中MyClass實例中第一個元素變成了5,但con1沒有改變,即實現了深拷貝。   BaseObject的實現:   復制代碼 /// <summary> /// BaseObject class is an abstract class for you to derive from. /// Every class that will be dirived from this class will support the  /// Clone method automaticly.<br> /// The class implements the interface ICloneable and there  /// for every object that will be derived <br> /// from this object will support the ICloneable interface as well. /// </summary>   public abstract class BaseObject : ICloneable {     /// <summary>     /// Clone the object, and returning a reference to a cloned object.     /// </summary>     /// <returns>Reference to the new cloned      /// object.</returns>     public object Clone()     {         //First we create an instance of this specific type.         object newObject  = Activator.CreateInstance( this.GetType() );           //We get the array of fields for the new type instance.         FieldInfo[] fields = newObject.GetType().GetFields();           int i = 0;           foreach( FieldInfo fi in this.GetType().GetFields() )         {             //We query if the fiels support the ICloneable interface.             Type ICloneType = fi.FieldType.                         GetInterface( "ICloneable" , true );               if( ICloneType != null )             {                 //Getting the ICloneable interface from the object.                 ICloneable IClone = (ICloneable)fi.GetValue(this);                   //We use the clone method to set the new value to the field.                 fields[i].SetValue( newObject , IClone.Clone() );             }             else             {                 // If the field doesn't support the ICloneable                  // interface then just set it.                 fields[i].SetValue( newObject , fi.GetValue(this) );             }               //Now we check if the object support the              //IEnumerable interface, so if it does             //we need to enumerate all its items and check if              //they support the ICloneable interface.             Type IEnumerableType = fi.FieldType.GetInterface                             ( "IEnumerable" , true );             if( IEnumerableType != null )             {                 //Get the IEnumerable interface from the field.                 IEnumerable IEnum = (IEnumerable)fi.GetValue(this);                   //This version support the IList and the                  //IDictionary interfaces to iterate on collections.                 Type IListType = fields[i].FieldType.GetInterface                                     ( "IList" , true );                 Type IDicType = fields[i].FieldType.GetInterface                                     ( "IDictionary" , true );                   int j = 0;                 if( IListType != null )                 {                     //Getting the IList interface.                     IList list = (IList)fields[i].GetValue(newObject);                       foreach( object obj in IEnum )                     {                         //Checking to see if the current item                          //support the ICloneable interface.                         ICloneType = obj.GetType().                             GetInterface( "ICloneable" , true );                                                  if( ICloneType != null )                         {                             //If it does support the ICloneable interface,                              //we use it to set the clone of                             //the object in the list.                             ICloneable clone = (ICloneable)obj;                               list[j] = clone.Clone();                         }                           //NOTE: If the item in the list is not                          //support the ICloneable interface then in the                          //cloned list this item will be the same                          //item as in the original list                         //(as long as this type is a reference type).                           j++;                     }                 }                 else if( IDicType != null )                 {                     //Getting the dictionary interface.                     IDictionary dic = (IDictionary)fields[i].                                         GetValue(newObject);                     j = 0;                                          foreach( DictionaryEntry de in IEnum )                     {                         //Checking to see if the item                          //support the ICloneable interface.                         ICloneType = de.Value.GetType().                             GetInterface( "ICloneable" , true );                           if( ICloneType != null )                         {                             ICloneable clone = (ICloneable)de.Value;                               dic[de.Key] = clone.Clone();                         }                         j++;                     }                 }             }             i++;         }         return newObject;     } } 復制代碼 浮躁的人容易問:我到底該學什麼;----別問,學就對了; 浮躁的人容易問:JS有錢途嗎;----建議你去搶銀行; 浮躁的人容易說:我要中文版!我英文不行!----不行?學呀! 浮躁的人分兩種:只觀望而不學的人;只學而不堅持的人; 浮躁的人永遠不是一個高手。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved