一個克隆物件的C#基類 (轉)
一個克隆的基類: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介面的抽象類。現在或許你正在問自己: 什麼是預設行為? 那麼我很高興你這樣詢問。 克隆的預設行為,是採用以下的規則來克隆類中的每一個欄位:
- 檢視一下類中的每一個欄位是否支援
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 介面,克隆方法將偵測該欄位,輪詢所有項,並同樣地試圖對他們進行克隆。
實現
///
/// BaseObject類是一個用來繼承的抽象類。 /// 每一個由此類繼承而來的類將自動支援克隆方法。
/// 該類實現了Icloneable介面,並且每個從該物件繼承而來的物件都將同樣地 /// 支援Icloneable介面。 public abstract class BaseObject : ICloneable { /// /// 克隆物件,並返回一個已克隆物件的引用 ///
/// {
//首先我們建立指定型別的一個例項
//我們取得新的型別例項的欄位陣列。 int i = 0; foreach( FieldInfo fi in this.GetType().GetFields() ) { //我們判斷欄位是否支援ICloneable介面。
GetInterface( "ICloneable" , true ); if( ICloneType != null ) {
//取得物件的Icloneable介面。
//我們使用克隆方法給欄位設定新值。 fields[i].SetValue( newObject , IClone.Clone() ); } else {
// 如果該欄位部支援Icloneable介面,直接設定即可。 } //現在我們檢查該物件是否支援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介面。
foreach( object obj in IEnum ) {
//檢視當前項是否支援支援ICloneable 介面。 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 介面。 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/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- js克隆一個物件JS物件
- 物件與XML之間互相轉化的一個基類物件XML
- .NET物件克隆的深究 (轉)物件
- js如何克隆一個節點物件JS物件
- VB.NET中物件的克隆 (轉)物件
- 物件的克隆——原型模式(一)物件原型模式
- 一個POP3客戶端的C#類 (轉)客戶端C#
- C# 將一個物件轉換為指定型別C#物件型別
- Java中的物件“克隆”Java物件
- js物件的深度克隆!JS物件
- 使用c#強大的表示式樹實現物件的深克隆C#物件
- JS 物件合併與克隆方法的分類與比較JS物件
- 克隆一個陣列的方法陣列
- Java基礎-設計一個Java類所需的方法(轉)Java
- 原生js實現物件的深克隆以及淺克隆JS物件
- js深度克隆物件JS物件
- 物件如何深度克隆物件
- javascript 深度克隆物件JavaScript物件
- c#如何只能建立類的一個例項(一)C#
- C#學習筆記(一)--- 物件導向的思想和類的定義、物件的建立C#筆記物件
- c#一個批次下載圖片的類C#
- 詳解 Java 中的物件克隆Java物件
- 如何實現物件的深度克隆物件
- 物件的克隆——原型模式(四)物件原型模式
- 物件的克隆——原型模式(三)物件原型模式
- 物件的克隆——原型模式(二)物件原型模式
- xlua中lua物件到c#物件的轉型物件C#
- JavaScript深層克隆物件JavaScript物件
- JS型別判斷、物件克隆、陣列克隆JS型別物件陣列
- 洗牌的一個C++類! (轉)C++
- C#中介面、基類與類C#
- C#中基類的重寫C#
- java基礎學習之一:物件和類Java物件
- C#中類和結構的一個區別...C#
- 一個C#封裝的加密解密類程式碼C#封裝加密解密
- Delphi中的類和物件 (轉)物件
- vue 克隆物件時遇到的問題Vue物件
- Java 的常見 API 與物件克隆)JavaAPI物件