2010-07-03 75 views
5

我想我一定是失去了一些東西,我爲什麼不能編譯這個:爲什麼你不能強制約束型開放泛型?

class Foo<T> where T : Bar 
{ 
    T Bar; 
} 

abstract class Bar 
{ } 

class MyBar : Bar 
{ } 

static void Main(string[] args) 
{ 
    var fooMyBar = new Foo<MyBar>(); 
    AddMoreFoos(fooMyBar); 
} 

static void AddMoreFoos<T>(Foo<T> FooToAdd) where T : Bar 
{ 
    var listOfFoos = new List<Foo<Bar>>(); 
    listOfFoos.Add(FooToAdd); //Doesn't compile 
    listOfFoos.Add((Foo<Bar>)FooToAdd); //doesn't compile 
} 

回答

9

你做的事情有點更加混亂比他們需要通過這裏使用列表...這是最容易看到的效果是這樣的:

// This won't compile 
Foo<Bar> fooBar = new Foo<MyBar>(); 

鑑於這不會編譯,那就不足爲奇了,你不能將Foo<MyBar>加到List<Foo<Bar>>

那麼爲什麼不是Foo<MyBar> a Foo<Bar>?因爲泛型類不是協變的。

通用差異僅在C#4中引入 - 它僅適用於接口和委託。所以,你可以(在C#4)做:

IEnumerable<MyBar> x = new List<MyBar>(); 
IEnumerable<Bar> y = x; 

,但你不能這樣做:

IList<MyBar> x = new List<MyBar>(); 
IList<Bar> y = x; 

我有整整談變化,你可以從NDC 2010 video site下載 - 只需搜索「方差」。

3

它不會因爲編譯如果你打電話給你的方法用Foo<int>則調用將失敗:您嘗試爲您的通用參數假定特定的類型。

你需要的是用var listOfFoos = new List<Foo<T>>()代替,然後Add應該工作。 (編輯:同樣,如果你使用了Foo<T> - 但你仍然不能假設你的代碼中的TBar)。編輯:同樣,如果你使用Foo<T> - 但你仍然不能假設你的代碼是TBar)。

+0

'如果你打電話給你的方法使用Foo 那麼調用會失敗'=>但是這個調用不會編譯,因爲通用約束,其中T:Bar,不是?但是,新列表+1 >(),因爲這實際上解決了我真正的問題! – 2010-07-03 15:26:01

+0

約束的好處。如果我解決了你的問題,爲什麼你接受了其他答案?(Jon Skeet or not!;-)) – 2010-07-03 15:34:16