2011-12-25 136 views
14

我有一個基類C#繼承。從基類派生類

public class A 
{ 
    public string s1; 
    public string s2; 
} 

我也有一個派生類:

public class B : A 
{ 
    public string s3; 
} 

假設我的程序創建的類A的一個實例

A aClassInstance = new A(); 

一些參數被設定:

aClassInstance.s1 = "string 1"; 
aClassInstance.s2 = "string 2"; 

在這一點上我想創建B類的實例,但是,我想B到已經有我的A類的實例的值

這並不工作:

public B bClassInstance = new B(): 
bClassInstance = (B)aClassInstance; 

也不是這:

製造A類內的克隆方法

public B cloneA() {  
    A a = new A(); 
    a = (A)this.MemberwiseClone() 
    return(B)a; 
} 

的VS代碼採用上述兩種的 - BU T I得到運行時錯誤

請幫

+2

克隆時要小心 - 特別是如果您的類具有可變引用類型的字段。決定是否需要深度克隆或淺層克隆,並將其記錄下來。 – TrueWill 2011-12-25 22:39:14

+1

沒錯。這個特定的類沒有引用,所以淺層的克隆就適用於它。我發現淺VS這裏深克隆一個很好的職位有興趣的人:http://itpksingh.blogspot.com/2009/08/shallow-copyingdeep-copyingobject.html – Sam 2011-12-26 00:22:32

+0

發現使用ValueInjector的解決方案。 StackOverFlow不允許我「回答我自己的問題」。一旦確定,將發佈全部細節。 – Sam 2011-12-26 01:35:42

回答

21

您遇到的基本問題是,您必須構造一個類型爲B(其中包含導致類型爲A的屬性)的實例。您的方法克隆A實例將不起作用,因爲這會爲您提供A類型的實例,您無法將其轉換爲B

我會寫類A和B的構造函數,它需要一個類型爲A的參數。類B的構造函數只是將值傳遞給它的基類A.A類的構造函數知道如何領域複製到其自身:

class A { 
    public A(A copyMe) { 
     s1 = copyMe.s1; 
     ... 
    } 

class B : A { 

    public B(A aInstance) : base(aInstance) { 
    } 

} 

使用這種方式:

​​

編輯

當你不想有改變A的構造函數在添加新字段或道具時,可以使用反射來複制屬性。無論是使用自定義屬性來裝點你想要的東西拷貝或複製的A剛纔的所有道具/字段:

public A (A copyMe) { 
    Type t = copyMe.GetType(); 
    foreach (FieldInfo fieldInf in t.GetFields()) 
    { 
     fieldInf.SetValue(this, fieldInf.GetValue(copyMe)); 
    } 
    foreach (PropertyInfo propInf in t.GetProperties()) 
    { 
     propInf.SetValue(this, propInf.GetValue(copyMe)); 
    } 
} 

我沒有帶試過的代碼,但問題應該變得清晰起來。

+0

我想升級它,以便每個成員不必單獨複製:class A { public A(A copyMe){ s1 = copyMe.s1; (A)copyMe.MemberwiseClone()應返回我需要的我的調用A的淺度克隆。現在我們需要做的就是把它傳回給B的構造函數......問題就是這樣。 遺憾的是我們不能做到這一點: 類A { 公開發行A(A copyMe){ 此=(A)copyMe.MemberwiseClone() }} ... } – Sam 2011-12-26 00:47:08

+1

@Sam:問題是,您必須構造一個B類型的對象。因爲A是B的一部分,所以您必須找到一種設置新B實例的屬性的方法,它們屬於A類型。您的* clone A *方法不會奏效,因爲它給了你一個類型A的實例,你需要一個B類型的實例!你可以做的是在A的構造函數中使用反射。我將更新我的答案以反映這一點。 – Jan 2011-12-26 11:58:33

8

您可以創建A類的通用克隆方法:

 public T Clone<T>() where T : A, new() { 
      return new T() { a = this.a, b = this.b}; 
    } 

或者,如果你想克隆擴展:

 public T Clone<T>() where T : A, new() { 
      var result = new T(); 
      this.CopyTo(result); 
      return result; 
    } 

    protected virtual void CopyTo(A other) { 
      other.a = this.a; 
      other.b = this.b; 
    } 

您這樣使用:

 A a = new A(); 
    // do stuff with a 
    // Create a B based on A: 
    B b = a.Clone<B>(); 

請注意:在您的示例中,新A()和MemberwiseClone都將創建A類新對象。

如果您不想自己編寫複製方法,則可以查看工具像AutoMapper

+0

謝謝! 在這個例子中,我必須設置所有成員(如a = this.a,b = this.b等)。如果班級有多個成員,無論如何避免編碼每個成員? (如果我決定添加另一個成員,我必須在克隆函數中設置它) – Sam 2011-12-26 00:21:23

+0

您可以使用反射來構建某些東西(循環遍歷所有字段並複製它們),但根據我知道的經驗,您最好控制自己的複製。有時你需要一個淺拷貝,對於一些需要深拷貝的對象。 – GvS 2011-12-26 08:39:19

+0

爲什麼不'other =(A)這個。MemberwiseClone();'在上面工作(而不必設置每個屬性)。我試圖避免設置每個屬性或使用反射。 – PeterX 2015-03-03 00:20:52

1

玩耍和閱讀的一切後,我可以通過GVS和Jan的工作讓我的眼睛,上述兩種解決方案。 但是,我想達到的最終結果不是強制寫出Copy方法中的每個成員。

爲什麼: 一)如果該類編輯和添加另一個對象,複製方法將不得不進行更新。如果有人更新課程,他們可能會忘記這樣做。

b)中可能有很多成員,並賦予它們可能是耗時的。

三)它只是沒有「感覺」的權利。 (可能因爲我很懶惰)。

幸運的是,我不是唯一一個有同樣的想法。通過ValueInjector發現一個非常非常簡單的解決方案。 (在這些板子上已經討論過很多)。

A a = new A(); 
a.s1 = "..."; 


B b = new B(); 
b.InjectFrom(a); 

就是這樣:)

很明顯,你必須包括:

得到DLL(http://valueinjecter.codeplex.com/documentation)

代碼變得之後:

using Omu.ValueInjecter; 

不要忘記將它添加到引用。