2012-02-20 120 views
7

是否可以創建一個必須返回派生類實例的抽象方法?我可以這樣做:返回派生類實例的抽象方法

abstract class Base 
{ 
    public abstract Base GetObj(); 
} 

class Derived : Base 
{ 
    public Derived() { } 

    public override Base GetObj() 
    { 
     return new Derived(); 
    } 
} 

但我不知道是否有辦法做到這一點,使得Derived::GetObj()被迫返回Derived

謝謝。

+1

請參閱:http://blogs.msdn.com/b/ericlippert/archive/2011/02/03/curiouser-and-curiouser.aspx,瞭解需要考慮的缺陷和挑戰。 – 2012-02-20 12:59:05

+0

感謝您的鏈接。有趣的閱​​讀。 – Eric 2012-02-20 13:05:08

回答

16

使用泛型應該使這成爲可能:

abstract class Base<T> 
    where T : Base<T> 
{ 
    public abstract T GetObj(); 
} 

class Derived : Base <Derived> 
{ 
    public Derived() { } 

    public override Derived GetObj() 
    { 
     return new Derived(); 
    } 
} 

你甚至可以簡化這個更(如果所有派生的實例與默認構造函數創建):

abstract class Base<T> 
    where T : Base<T>, new() 
{ 
    public static T GetObj() 
    { 
     return new T(); 
    } 
} 

class Derived : Base<Derived> 
{ 
    public Derived() { } 
} 
+3

請注意,這隻會強制* first *派生類自行返回。第二個派生類可以返回第一個。 – 2012-02-20 12:56:15

+0

謝謝,這看起來正是我所需要的。我不認爲有什麼辦法可以使這種靜態方法? – Eric 2012-02-20 13:02:22

+0

是的,這個方法可以是靜態的,在這種情況下,你有一個工廠。並且將能夠使用'Derived.GetObj()'。 – Lukazoid 2012-02-20 13:06:46

6

你是什麼幾乎但不完全是一個抽象工廠。我首先要說的是,你應該把它留給派生類的實現者來讓它正確,或者只是相信他們會。

另一個答案顯示了所謂的奇怪的循環模板模式。你有一個基類試圖使用類型系統來強制派生類型在某些輸入或輸出位置使用自己的地方。

public abstract class Foo<T> where T : Foo<T> 
public class Bar : Foo<Bar> 

這個想法可能適用於其他語言。只有在人們正確使用它的情況下,它才能在C#中工作。有了Bar的上述定義,現在我也可以有

public class Baz : Foo<Bar> 

這是完全合法的。 Bar是一個Foo<Bar>,這是巴茲使用它的全部。沒有要求巴茲實際使用Foo<Baz>

C#中的類型系統根本無法執行您想實施的操作。即使採用這種模式,您仍然處於和以前一樣的位置。您仍然必須相信派生類的實現者才能正確執行。

有關此主題的更多信息,請參閱this blog