2014-06-13 81 views
0

我在基類中有一個類層次結構和一個靜態方法,所以子類也有這種靜態方法。我喜歡這樣定義將靜態方法的約束返回類型改爲當前類的類型

public static IEnumerable<T> GetList<T>() 
    where T : BaseClass, new() 
{ 
    return new List<T>() { ... }; 
} 

一個靜態方法,所以我將能夠調用

var list = ChildClass.GetList(); 

和列表將IEnumerable<ChildClass>。但我不知道如何告訴編譯器推斷泛型類型是類我從呼叫類型,所以這種用法產生一個錯誤,我必須把它糾正以某種方式冗餘

var list = ChildClass.GetList<ChildClass>(); 

我可以使用擴展方法(他們有this參數,允許編譯器趕上),但我想這樣做沒有實例化ChildClass

有沒有辦法做到這一點,而不重複?

回答

2

你不能讓編譯器推斷出你從技術上,因爲你總是從方法中定義的類調用調用類。

編譯器允許你使用一個派生類的名字,而不是僅僅是一個方便。

1

如果你可以用一個醜陋的黑客攻擊過,你可以讓BaseClass本身一般,並通過子類的類型作爲參數傳遞給泛型參數,如:

class BaseClass<T> where T : BaseClass<T>, new() 
{ 
    public static IEnumerable<T> GetList() 
    { 
     return new List<T>() { new T() }; // whatever 
    } 
} 

class Child : BaseClass<Child> 
{ 

} 

class Child2 : BaseClass<Child2> 
{ 

} 

現在Child.GetList()返回IEnumerable<Child>Child2.GetList()返回IEnumerable<Child2>

+0

直到有人創建了一個'EvilChild:BaseClass ' – Servy

+0

@Servy是的,這就是爲什麼醜陋的黑客被稱爲醜陋和黑客。 – sloth

+0

有趣,謝謝。 :-) –

1

如果你想知道爲什麼編譯器不能解析的類型,請繼續閱讀:

首先靜態方法綁定到類型不是對象。所以這裏不能有任何多態行爲。所以,你有一個孩子,基類層次結構的事實在這裏並不重要,因爲這些方法被綁定到兩個完全不同的實體。

真正的問題在於C#編譯器的類型推斷功能。你必須給編譯器一些關於T類型的信息。否則它不能推斷它。

因爲C#類型推斷從右向左工作,所以不能在左側給出此信息。換句話說:

var ints = new {}; 

完全沒問題。因爲右側的類型是匿名方法,並且整數被解析爲一個。但是:

int[] ints = new [] {}; 

不行。編譯器會抱怨「沒有找到隱式類型數組的最佳類型」。換句話說,編譯器不能使用左側的信息來確定類型應該在右側。

在你的問題

var list = ChildClass.GetList(); 

不給編譯器什麼T是任何信息!即使你有類型而不是var也沒有什麼區別。

+0

很好,謝謝你的回答!我知道從左到右的干擾,但我不確定它在那裏有多大用處。如果你考慮鏈調用list.Where(...)。Select(...)',那麼類型信息實際上流向右邊 - 你不必在上一次select中鍵入lambdas,因爲你知道什麼是list '是。以同樣的方式,可以成爲'this'類型的''this'關鍵字的等價物,這將在靜態方法中可用。當然,我明白,鑑於靜態方法是「繼承的」這一事實本身就是一種令人驚訝的事情,因此這將是過於複雜的事情。 :-) –

相關問題