2008-09-05 52 views
44

C#不要求你指定一個泛型類型參數,如果編譯器可以推斷它,比如:爲什麼C#不支持類構造函數中的隱含泛型類型?

List<int> myInts = new List<int> {0,1,1, 
    2,3,5,8,13,21,34,55,89,144,233,377, 
    610,987,1597,2584,4181,6765}; 

//this statement is clunky 
List<string> myStrings = myInts. 
    Select<int,string>(i => i.ToString()). 
    ToList<string>(); 

//the type is inferred from the lambda expression 
//the compiler knows that it's taking an int and 
//returning a string 
List<string> myStrings = myInts. 
    Select(i => i.ToString()). 
    ToList(); 

這是需要匿名類型,你不知道類型參數會是什麼(在intellisense中顯示爲'a),因爲它是由編譯器添加的。

類級別類型參數不要讓你這樣做:

//sample generic class 
public class GenericDemo<T> 
{ 
    public GenericDemo (T value) 
    { 
     GenericTypedProperty = value; 
    } 

    public T GenericTypedProperty {get; set;} 
} 

//why can't I do: 
int anIntValue = 4181; 
var item = new GenericDemo(anIntValue); //type inference fails 

//however I can create a wrapper like this: 
public static GenericDemo<T> Create<T> (T value) 
{ 
    return new GenericDemo<T> (value); 
} 

//then this works - type inference on the method compiles 
var item = Create(anIntValue); 

爲什麼不C#支持這一類級別泛型類型推斷?

+0

爲什麼這個問題有一個投票結果反對它作爲[爲什麼不能C#構造函數推斷類型?](http://stackoverflow.com/questions/3570167)當這個問題是兩年更近?當然這是重複的? – Keith 2013-07-04 09:06:54

+0

我認爲其他問題更簡潔,它有一個更好的答案。 – Sam 2013-10-08 04:13:01

回答

25

其實你的問題還不錯。過去幾年來我一直在使用泛型編程語言,雖然我從來沒有實際開發它(可能永遠也不會),但我對泛型類型推理有很多想法,而且我的首要任務之一是一直以來都允許構建類而不必指定泛型類型。

C#根本沒有一套規則來使這成爲可能。我認爲開發者從來沒有看到包括這個的必要性。其實,下面的代碼會非常接近你的主張並解決問題。所有C#需求都是一種額外的語法支持。

class Foo<T> { 
    public Foo(T x) { … } 
} 

// Notice: non-generic class overload. Possible in C#! 
class Foo { 
    public static Foo<T> ctor<T>(T x) { return new Foo<T>(x); } 
} 

var x = Foo.ctor(42); 

由於這段代碼實際工作,我們已經表明,問題不是語義之一,而僅僅是一個缺乏支持。我想我必須收回我之前的發帖。 ;-)

11

爲什麼C#不支持這個類級別的泛型類型推斷?

因爲它們通常是不明確的。相比之下,類型推斷對於函數調用是微不足道的(如果所有類型都出現在參數中)。但是對於構造函數調用(爲了討論的緣故,函數是光榮的),編譯器必須同時解析多個級別。一個級別是類級別,另一個級別是構造函數參數級別。我相信解決這個問題在算法上並不重要。直覺上,我會說它甚至是NP完整的。

爲了說明一種極端情況下的分辨率是不可能的,想象下面的類,並告訴我,編譯器應該做的:

class Foo<T> { 
    public Foo<U>(U x) { } 
} 

var x = new Foo(1); 
2

感謝康拉德,這是一個很好的響應(+1),但只是爲了擴大在上面。

讓我們假設C#有一個明確的構造函數:

//your example 
var x = new Foo(1); 

//becomes 
var x = Foo.ctor(1); 

//your problem is valid because this would be 
var x = Foo<T>.ctor<int>(1); 
//and T can't be inferred 

你說得第一構造無法推斷。

現在,讓我們回到類

class Foo<T> 
{ 
    //<T> can't mean anything else in this context 
    public Foo(T x) { } 
} 

//this would now throw an exception unless the 
//typeparam matches the parameter 
var x = Foo<int>.ctor(1); 

//so why wouldn't this work? 
var x = Foo.ctor(1); 

當然,如果我加入你的構造回(及其替代型),我們有一個模糊的呼喚 - 完全一樣,如果一個正常的方法重載不能解決。

相關問題