为什么不能将受约束的开放泛型类型转换为约束类型?

时间:2010-07-03 14:50:46

标签: c# generics

我想我必须遗漏一些东西,为什么我不能编译它:

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
}

2 个答案:

答案 0 :(得分:9)

你在这里使用一个列表让事情变得更加困惑......最简单的方法是看到这种效果:

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

鉴于这不能编译,因此您无法将Foo<MyBar>添加到List<Foo<Bar>>

就不足为奇了

那么为什么不是Foo<MyBar>一个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下载 - 只需搜索“差异”。

答案 1 :(得分:3)

它无法编译,因为如果您使用Foo<int>调用方法,则调用将失败:您正在尝试为通用参数设置特定类型。

您需要的是使用var listOfFoos = new List<Foo<T>>(),然后Add应该有效。

(编辑:同样,如果您使用Foo<T>,演员阵容也会有效 - 但您仍然无法在代码中假设TBar。)