2011-11-02 64 views
4

我有一個類層次結構,看起來像這樣:類型推論的方法,以仿製藥和類繼承

class Base<TElement> 
{ 
    public TElement Element { get; set; } 
} 

class Concrete : Base<string> 
{ 
} 

我想寫接受Base子類的方法:

public TConcrete DoSomething<TConcrete, TElement>() 
    where TConcrete : Base<TElement> 
{ 
} 

有什麼方法可以定義DoSomething,而不必定義TElement

理想的解決方案是,如果編譯器可以自動計算TElement,所以調用代碼是這樣的:

var item = DoSomething<Concrete>(); 

我使用C#4.0。

+0

'TConcrete'和'TElement'類型與返回或參數類型無關? –

+0

TConcrete是返回類型,我編輯了我的問題 – kshahar

+0

它看起來像你想要[更高級的類型](http://en.wikipedia.org/wiki/Kind_(type_theory)) c#,語言不支持 –

回答

4

這是不可能的,原因如下:

  1. 隨着C#4,類型推斷是「全有或全無」 - 編譯器不能推斷出一些通用的參數而不是其他。
  2. 從C#4開始,不可能指定通用「通配符」,如where TConcrete : Base<???>

以下是一些解決方法。

非通用基類型:創建基類或接口類型,即而不是通用。這是一種常見的模式;例如IEnumerable<T> : IEnumerable


協變界面:用C#4通用接口協方差,你可以創建一個類型安全的解決方案,不需要與「醜」非普通會員塞滿您的類型:

public interface IBase<out TElement> 
{ 
    TElement Element { get; } 
} 

class Base<TElement> : IBase<TElement> 
{ 
    public TElement Element { get; set; } 
} 

class Concrete : Base<string> { } 

然後:

// Won't work with value types. 
public TConcrete DoSomething<TConcrete>() 
    where TConcrete : IBase<object> { } 

,並調用它像:

var item = DoSomething<Concrete>(); 
+0

您的上一個建議(協變接口)解決了我的問題。謝謝! – kshahar

1

如果您讓Base繼承非泛型類或實現非泛型接口,則可以將方法限制爲該類型。

否則,沒有。如果可行,方法中的TConcrete.Element屬性將沒有類型。
如果你寫

public TConcrete DoSomething<TConcrete>() where TConcrete : Base<> //Illegal! 
{ 
    TConcrete c = ...; 
    var b = c.Element; //What type is that variable? 
} 
0

如果DoSomething不知道(或護理)會發生什麼,什麼TElement是,你可能要考慮創建不帶類型參數的父類:

class Base 
{ 
} 

class Base<TElement> : Base 
{ 
    public TElement Element { get; set; } 
} 

然後,您的DoSomething方法將在類Base上操作。

如果DoSomething需要知道類型參數,那麼沒有,沒有辦法做你想要的東西&你需要提供它。