熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> .NET編程 >> 正文

C#中實現任意類的完美克隆

2022-06-13   來源: .NET編程 

  簡介

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

  為實現一個類你究竟有多少次要實現ICloneable接口 而且每一次都寫相同的代碼或為每個類寫特定的代碼而且當你的類加入一個新的字段時往往會忘記更新這個新字段的克隆方法如果我沒說錯的話這種時候往往會帶來惱人的bugs

  這是我的類得以存在的原因 藉由反射機制的小小幫助我建立了一個用缺省行為實現了ICloneable接口的抽象類現在或許你正在問自己: 什麼是缺省行為? 那麼我很高興你這樣詢問 克隆的缺省行為是采用以下的規則來克隆類中的每一個字段

  ·查看一下類中的每一個字段是否支持ICloneable接口

  如果某字段不支持ICloneable接口那麼該字段將以常規方式處理這意味著如果該字段是一個值類型那麼該值被拷貝如果該字段是一個引用類型克隆的字段將指向同一個對象

  如果該字段支持ICloneable接口我們將使用其本身的Clone方法對其進行克隆

  如果該字段支持IEnumerable接口我們需要檢查他是否支持IList 或 IDictionary 接口如果支持那麼我們迭代該集件並且查看集合的每一項是否支持Cloneable接口

  如何使用

  讓你的類支持Icloneable接口所要做的就是將你的類繼承自如下所述的BaseObject類

  public class MyClass : BaseObject

  {

  public string myStr =test;

  public int id;

  }

  public class MyContainer : BaseObject

  {

  public string name = test;

  public MyClass[] myArray= new MyClass[];

  public class MyContainer()

  {

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

  {

  thismyArray[I] = new MyClass();

  }

  }

  }

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

  static void Main(string[] args)

  {

  MyContainer con = new MyContainer();

  MyContainer con = (MyContainer)conClone();

  conmyArray[]id = ;

  }

  當監測con實例時你將會看到MyClass實例的第一項已經變為而con實例卻沒有改變這樣你將明白加入到類中的任意支持ICloneable接口的字段將被同樣地克隆而且如果該字段支持IList 或 IDictionary 接口克隆方法將偵測該字段輪詢所有項並同樣地試圖對他們進行克隆

  BaseObject類的完整實現代碼

  /// <summary>

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

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

  /// 該類實現了Icloneable接口並且每個從該對象繼承而來的對象都將同樣地

  /// 支持Icloneable接口

  /// </summary>

  public abstract class BaseObject : ICloneable

  {

  /// <summary>

  /// 克隆對象並返回一個已克隆對象的引用

  /// </summary>

  /// <returns>引用新的克隆對象</returns>

  public object Clone()

  {

  //首先我們建立指定類型的一個實例

  object newObject = ActivatorCreateInstance(thisGetType());

  //我們取得新的類型實例的字段數組

  FieldInfo[] fields = newObjectGetType()GetFields();

  int i = ;

  foreach (FieldInfo fi in thisGetType()GetFields())

  {

  //我們判斷字段是否支持ICloneable接口

  Type ICloneType = fiFieldTypeGetInterface(ICloneable true);

  if (ICloneType != null)

  {

  //取得對象的Icloneable接口

  ICloneable IClone = (ICloneable)fiGetValue(this);

  //我們使用克隆方法給字段設定新值

  fields[i]SetValue(newObject ICloneClone());

  }

  else

  {

  // 如果該字段部支持Icloneable接口直接設置即可

  fields[i]SetValue(newObject fiGetValue(this));

  }

  //現在我們檢查該對象是否支持IEnumerable接口如果支持

  //我們還需要枚舉其所有項並檢查他們是否支持IList 或 IDictionary 接口

  Type IEnumerableType = fiFieldTypeGetInterface(IEnumerable true);

  if (IEnumerableType != null)

  {

  //取得該字段的IEnumerable接口

  IEnumerable IEnum = (IEnumerable)fiGetValue(this);

  Type IListType = fields[i]FieldTypeGetInterface(IList true);

  Type IDicType = fields[i]FieldTypeGetInterface(IDictionary true);

  int j = ;

  if (IListType != null)

  {

  //取得IList接口

  IList list = (IList)fields[i]GetValue(newObject);

  foreach (object obj in IEnum)

  {

  //查看當前項是否支持支持ICloneable 接口

  ICloneType = objGetType()GetInterface(ICloneable true);

  if (ICloneType != null)

  {

  //如果支持ICloneable 接口

  //我們用它李設置列表中的對象的克隆

  ICloneable clone = (ICloneable)obj;

  list[j] = cloneClone();

  }

  //注意如果列表中的項不支持ICloneable接口那麼

  //在克隆列表的項將與原列表對應項相同

  //(只要該類型是引用類型)

  j++;

  }

  }

  else if (IDicType != null)

  {

  //取得IDictionary 接口

  IDictionary dic = (IDictionary)fields[i]GetValue(newObject);

  j = ;

  foreach (DictionaryEntry de in IEnum)

  {

  //查看當前項是否支持支持ICloneable 接口

  ICloneType = deValueGetType()

  GetInterface(ICloneable true);

  if (ICloneType != null)

  {

  ICloneable clone = (ICloneable)deValue;

  dic[deKey] = cloneClone();

  }

  j++;

  }

  }

  }

  i++;

  }

  return newObject;

  }

  }


From:http://tw.wingwit.com/Article/program/net/201311/13699.html
    推薦文章
    Copyright © 2005-2022 電腦知識網 Computer Knowledge   All rights reserved.