一個克隆物件的C#基類 (轉)

amyz發表於2007-11-13
一個克隆物件的C#基類 (轉)[@more@]

一個克隆的基類:namespace prefix = o ns = "urn:schemas--com::office" />

By ?id=108738">Amir Harel

投遞於 2002, 12, 30

 

摘要一個實現ICloneable介面的類。

應用於:C#,

 

/CloneImpl_Class/Clone.zip"> files - 1.27 Kb

簡介

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

為實現一個類你究竟有多少次要實現ICloneable介面, 而且每一次都寫相同的程式碼,或為每個類寫特定的程式碼。而且,當你的類加入一個新的欄位時,往往會忘記這個新欄位的克隆方法。如果我沒說錯的話,這種時候往往會帶來惱人的s。

這是我的類得以存在的原因。 藉由反射機制的小小幫助,我建立了一個用預設行為實現了ICloneable介面的抽象類。現在或許你正在問自己: 什麼是預設行為? 那麼我很高興你這樣詢問。 克隆的預設行為,是採用以下的規則來克隆類中的每一個欄位:

  1. 檢視一下類中的每一個欄位是否支援ICloneable介面
  2. 如果某欄位不支援ICloneable介面那麼該欄位將以常規方式處理。這意味著,如果該欄位是一個值型別,那麼該值被複製;如果該欄位是一個引用型別,克隆的欄位將指向同一個物件。
  3. 如果該欄位支援ICloneable介面我們將使用其本身的Clone方法對其進行克隆。
  4. 如果該欄位支援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 介面,克隆方法將偵測該欄位,輪詢所有項,並同樣地試圖對他們進行克隆

實現

///


/// BaseObject類是一個用來繼承的抽象類。


 

/// 每一個由此類繼承而來的類將自動支援克隆方法。



/// 該類實現了Icloneable介面,並且每個從該物件繼承而來的物件都將同樣地


/// 支援Icloneable介面。


 

///


 


public abstract class BaseObject : ICloneable


{


  ///


/// 克隆物件,並返回一個已克隆物件的引用


  ///


  /// 引用新的克隆物件


 

  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;


  }


}


 

          (完)

 

參看原文:


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752019/viewspace-982126/,如需轉載,請註明出處,否則將追究法律責任。

相關文章