2010-11-11 78 views
11

我有一個叫Employee的類,有3個屬性叫做ID,NameDept。我需要執行CopyClone方法嗎?當我使用CopyClone方法時,我需要避免Casting?我將如何做到這一點?如何在類中實現克隆和複製方法?

示例:與DataTable相同,其具有DataTable.Copy()DataTable.Clone()

回答

13

您需要實現IClonable接口併爲克隆方法提供實現。 如果你想避免強制轉換,請不要執行此操作。

一個簡單的深度克隆方法可能是將對象序列化到內存然後反序列化它。您的類中使用的所有自定義數據類型都需要使用[Serializable]屬性進行序列化。對於克隆,你可以使用類似

public MyClass Clone() 
    { 
     MemoryStream ms = new MemoryStream(); 
     BinaryFormatter bf = new BinaryFormatter(); 

     bf.Serialize(ms, this); 

     ms.Position = 0; 
     object obj = bf.Deserialize(ms); 
     ms.Close(); 

     return obj as MyClass; 
    } 

如果你的類只有value types,那麼你可以使用一個copy constructor或只分配值在克隆方法的新對象。

+0

哇這是一個複雜的做法 - 爲什麼不只是使用複製構造函數? – 2010-11-11 09:05:51

+0

@Rowland它不適用於參考類型。無論如何編輯我的答案 – Midhat 2010-11-11 09:13:54

+1

@Rowland - 複製構造函數可能不會深層複製東西,並且需要在添加字段時進行維護。二進制序列化是進行深度複製的常用方式。 – 2010-11-11 09:13:58

2

檢查這個克隆的對象在C#中使用IL http://whizzodev.blogspot.com/2008/03/object-cloning-using-il-in-c.html

+0

也只有淺拷貝,如果你需要深拷貝,你將不得不編輯IL生成器來遞歸地瀏覽圖表。 – 2010-11-11 09:18:06

+0

還有更新的版本可用:http://whizzodev.blogspot.com/2008/06/object-deep-cloning-using-il-in-c_20.html – 2010-11-11 09:36:30

3

你必須使用ICloneable接口或者是不夠的,如果你只是有兩個方法稱爲CloneCopy是在一個通用的接口定義?

public class YourClass : ICloneable<YourClass> 
{ 
    // Constructor logic should be here 
    public YourClass Copy() { return this; }   
    public YourClass Clone() { return new YourClass(ID, Name, Dept); } 
} 

interface IClonable<T> 
{ 
    T Copy(); 
    T Clone(); 
} 

或者我誤解了一些東西?

我想說的是,你不必讓它變得比它更復雜?如果你需要你的對象符合某些你可以自己寫的東西,如果在.Net框架中指定的那個要複雜的情況。您還應該定義與CloneCopy的區別,即它們對您意味着什麼?我知道有幾個網站指定Clone是深度複製,Copy是淺度複製。

+2

唯一的問題是維護開銷。如果你添加一個新字段,你需要更新你的'CopyClone()'方法來合併它(以及它調用的構造函數)。如果你打算調用一個構造函數,而不是傳遞離散的字段,你應該傳遞整個對象,即:'返回new YourClass(this)' – 2010-11-11 09:16:00

+0

@Michael,這當然是正確的。但重要的是不要讓它變得更復雜,直到你真的需要它。而複製方法可能是錯誤的(會改變它:))。你可能可以改變IClonable接口,我有一個抽象類,它包含一個Clone方法,該方法使用反射或Midhat在下面寫的序列化模式。 – 2010-11-11 09:21:21

+0

甚至iam對差異文檔感到困惑。現場?。 – 2010-11-11 10:10:04

3

你的意思是,如何實現ICloneable.Clone()並讓它返回類本身的類型。

public class MyType : ICloneable 
{ 
    public MyType Clone() //called directly on MyType, returns MyType 
    { 
    return new MyType(/* class-dependant stuff goes here */); 
    } 
    object ICloneable.Clone() // called through ICloneable interface, returns object 
    { 
    return Clone(); 
    } 
} 
2

我經常看到複製構造函數被建議作爲克隆方法的替代方法,但除了密封類以外,行爲有很大不同。如果我有一個Type Car,它只支持屬性VIN,BodyColor和BodyStyle,以及支持InteriorFabric和SoundSystem的派生類型FancyCar,那麼接受Car類型對象並使用Car拷貝構造函數複製它的代碼將結束與汽車。如果FancyCar被傳遞給這樣的代碼,則產生的「重複」將是新車,其具有匹配原車的VIN,BodyColor和BodyStyle,但不具有任何InteriorFabric或SoundSystem。相比之下,代碼接受一個Car並在其上使用克隆方法,將FancyCar傳遞給代碼將導致FancyCar被生成。

除非有人想使用Reflection,否則任何克隆方法都必須在其基礎上調用base.MemberwiseClone。由於MemberwiseClone不是虛擬方法,因此我建議定義受保護的虛擬克隆方法;你也可以通過定義一個具有相同名稱的保護範圍的虛擬嵌套類來阻止任何子類調用MemberwiseClone(所以如果後代類試圖調用base。MemberwiseClone,它不會被解釋爲對虛擬類的無意義引用)。

2

下面的例子:

namespace XXX 
{ 
    [Serializable] 
    public class ItemChecklist : ICloneable 
    { 

     // [...here properties, attributes, etc....] 



     object ICloneable.Clone() 
     { 
      return this.Clone(); 
     } 
     public ItemChecklist Clone() 
     { 
      return (ItemChecklist)this.MemberwiseClone(); 
     } 


    } 
} 

即如果使用此功能,您將在「itemAdd」對象「itemTemp」以其所有值的完整副本。

ItemChecklist itemAdd = itemTemp.Clone();