无法将List <Foo>传递给期望List <IFoo>的方法,其中Foo:IFoo

The*_*uck 7 c# generics casting interface list

我有一个Foo实现IFoo接口的类.我有一个方法List<IFoo>作为参数.但是,它无法转换List<Foo>List<IFoo>- 这让我感到惊讶,因为Foo实现了IFoo接口.

我怎样才能解决这个问题,为什么会出现这种情况?(总是善于从错误中吸取教训)

Ree*_*sey 12

这是因为List<T>不协变.有关详细信息,请参阅C#中的协方差和逆变.

如果你可以让你的方法工作IEnumerable<T>,这将工作(你可以List<Foo>进入IEnumerable<IFoo>.NET 4,因为它已定义IEnumerable<out T>).

原因List<T>不是协变,顺便说一句,因为它没有定义只读合同.由于List<T>明确允许您添加元素(via Add(T)),因此允许协方差工作是不安全的.如果允许这样做,该方法将期望能够将类型的元素Bar(如果Bar派生自IFoo)添加到列表中,但是这会失败,因为列表实际上是a List<Foo>,而不是a List<IFoo>.由于IEnumerable<T>只允许您遍历列表,而不是修改它,因此它可以是协变的,并且在这种情况下只是按预期工作.

  • @The Duck:不.这就是为什么`IEnumerable <out T>`在定义中有"out"的原因.使用具有协方差的IEnumerable非常安全,正如您在这里所做的那样.只要你进行迭代,这就完美了(这就是语言现在支持它的原因!) (2认同)

SLa*_*aks 8

信不信由你,这不是类型安全的.

请考虑以下代码:

List<Foo> fooList = new List<Foo>();
List<IFoo> iFooList = fooList;    //Illegal

iFooList.Add(new SomeOtherFoo()); //That's not Foo!
Run Code Online (Sandbox Code Playgroud)

你要求协变转换; 这只适用于不可变类型.
此外,.Net仅支持接口的协方差.

将方法更改为a IEnumerable<IFoo>,它将起作用.