2009-09-02 97 views
1

我需要一種方法,在基類中創建一個對象的空克隆?例如:如何在基類中創建對象的克隆?

public class ChildClass : ParentClass 
{ 
    public ChildClass() 
    { 
    } 
} 
public class ParentClass 
{ 
    public SomeMethod() 
    { 
    // I want to create an instance of the ChildClass here 
    } 
} 

到目前爲止,我們有一個在父類中定義的抽象方法。而且,所有的孩子班級都實施它們。但是,所有的實現都是一樣的,只是一種不同的類型。

public class ChildClass : ParentClass 
{ 
    public ChildClass() 
    { 
    } 
    public ParentClass CreateEmpty() 
    { 
     return new ChildClass(); 
    } 
} 
public class ParentClass 
{ 
    public SomeMethod() 
    { 
    // I want to create an instance of the ChildClass here 
    ParentClass empty = CreateEmpty(); 

    } 
    public abstract ParentClass CreateEmpty(); 
} 

有沒有辦法從父類做到這一點,以便我不必爲每個不同的子類繼續實現相同的邏輯?請注意,可能會有更多級別的繼承(即ChildChildClass:ChildClass:ParentClass)。

回答

5

如果使用反射是沒有問題的話,你可以使用Activator類做到這一點:


//In parent class 
public ParentClass CreateEmpty() 
{ 
    return (ParentClass)Activator.CreateInstance(this.GetType()); 
} 

這將返回你想要的類型的空對象。注意這個方法不需要是虛擬的。

在另一方面,我認爲你目前的做法是完全沒有問題的代碼幾行是沒有那麼糟糕。

+0

啊,反思。直到現在,我還沒有發現它的真正用處。謝謝。 – bsh152s 2009-09-02 16:51:55

0

這有點實驗性的。我不知道這是否會導致循環依賴。有幾個月沒有碰過C#。

public class ParentClass<T> where T : ParentClass<T>, new() { // fixed 
    public ParentClass() { 
     var x = new T(); // fixed, was T.new() 
    } 
} 

public class ChildClass : ParentClass<ChildClass> { 
    public ChildClass() { } 
} 

否則去通過Ravadre的ReflectionCode。

+0

我認爲你的意思是「新T()」。 – 2009-09-02 16:21:22

+0

另外,你需要寫 「其中T:父類,新的()」 – 2009-09-02 16:23:51

+1

HTTP://ravadre.pastebin。com/m74c16ab - 這是一個完整的例子,它有一個問題 - 如何從ChildClass繼承? :)。它不像ParentClass那樣通用,所以這個解決方案會變得越來越複雜。 – 2009-09-02 16:28:00

0

可以使物體using the binary serializer的深克隆。

編輯:只注意到這個詞「空」旁邊的clone(我認爲是一個矛盾的說法)。不管怎樣,希望這個答案能夠幫助其他人找到這個問題,因爲他們正在尋找定期克隆。

0

我使用以下模式。

優點:

  • 這種模式保證克隆的類型安全的類私人和公共兩側。
  • 輸出類將始終正確。
  • 你永遠不會忘記重寫「克隆」方法。 「MyDerivedClass」永遠不會返回除「MyDerivedClass」之外的其他類。

缺點:

  • 對於一個類,你需要創建一個接口和兩個類(原型和決賽)

樣品:

// Common interface for cloneable classes. 
public interface IPrototype : ICloneable { 
    new IPrototype Clone(); 
} 

// Generic interface for cloneable classes. 
// The 'TFinal' is finaly class (type) which should be cloned. 
public interface IPrototype<TFinal> where TFinal : IPrototype<TFinal> { 
    new TFinal Clone(); 
} 

// Base class for cloneable classes. 
// The 'TFinal' is finaly class (type) which should be cloned. 
public abstract class PrototypeBase<TFinal> : IPrototype<TFinal> where TFinal : PrototypeBase<TFinal> { 
    public TFinal Clone() { 
     TFinal ret = this.CreateCloneInstance(); 
     if (null == ret) { 
      throw new InvalidOperationException("Clone instance was not created."); 
     } 

     this.FillCloneInstance(ret); 
     return ret; 
    } 

    // If overriden, creates new cloned instance 
    protected abstract TFinal CreateCloneInstance(); 

    // If overriden, fill clone instance with correct values. 
    protected abstract void FillCloneInstance(TFinal clone); 

    IPrototype IPrototype.Clone() { return this.Clone(); } 
    object ICloneable.Clone() { return this.Clone(); } 
} 

// Common interface for standalone class. 
public interface IMyStandaloneClass : IPrototype<IMyStandaloneClass> { 
    string SomeText{get;set;} 
    string SomeNumber{get;set;} 
} 

// The prototype class contains all functionality exception the clone instance creation. 
public abstract class MyStandaloneClassPrototype<TFinal> : PrototypeBase<TFinal>, IMyStandaloneClass where TFinal : MyStandaloneClassPrototype<TFinal> { 
    public string SomeText {get; set;} 
    public int SomeNumber {get; set} 

    protected override FillCloneInstance(TFinal clone) { 
     // Now fill clone with values 
     clone.SomeText = this.SomeText; 
     clone.SomeNumber = this.SomeNumber; 
    } 
} 

// The sealed clas contains only functionality for clone instance creation. 
public sealed class MyStandaloneClass : MyStandaloneClassPrototype<MyStandaloneClass> { 
    protected override MyStandaloneClass CreateCloneInstance() { 
     return new MyStandaloneClass(); 
    } 
} 

public interface IMyExtendedStandaloneClass : IMyStandaloneClass, IPrototype<IMyExtendedStandaloneClass> { 
    DateTime SomeTime {get; set;} 
} 

// The extended prototype of MyStandaloneClassPrototype<TFinal>. 
public abstract class MyExtendedStandaloneClassPrototype<TFinal> : MyStandaloneClassPrototype<TFinal> where TFinal : MyExtendedStandaloneClassPrototype<TFinal> { 
    public DateTime SomeTime {get; set;} 

    protected override FillCloneInstance(TFinal clone) { 
     // at first, fill the base class members 
     base.FillCloneInstance(clone); 

     // Now fill clone with values 
     clone.SomeTime = this.SomeTime; 
    } 
} 

public sealed class MyExtendedStandaloneClass : MyExtendedStandaloneClassPrototype<TFinal> { 
    protected override MyExtendedStandaloneClass CreateCloneInstance() { 
     return new MyExtendedStandaloneClass 
    } 
}