不能传递List到一个期望列表的方法,其中Foo: IFoo

本文关键字:IFoo Foo 列表 期望 方法 一个 其中 List 不能 | 更新日期: 2023-09-27 18:04:15

我有一个类Foo实现IFoo接口。我有一个以List<IFoo>为参数的方法。然而,它不能从List<Foo>转换到List<IFoo> -这让我感到惊讶,因为Foo实现了IFoo接口。

如何解决这个问题,为什么会发生这种情况?(从错误中吸取教训总是好的)

不能传递List<Foo>到一个期望列表<IFoo>的方法,其中Foo: IFoo

这是因为List<T>不是协变的。详细信息请参见c#中的协方差和逆变。

如果你可以让你的方法在IEnumerable<T>上工作,这将工作(你可以在。net 4中将List<Foo>传递给IEnumerable<IFoo>,因为它被定义为IEnumerable<out T>)。

List<T>不是协变的原因,顺便说一句,是因为它没有定义只读契约。由于List<T>显式地允许您添加元素(通过Add(T)),因此允许协方差工作是不安全的。如果允许这样做,则该方法期望能够将类型为Bar的元素(如果Bar派生自IFoo)添加到列表中,但这将失败,因为列表实际上是 List<Foo>,而不是List<IFoo>。由于IEnumerable<T>只允许您遍历列表,但不允许修改它,因此它可以是协变的,并且在本例中按预期工作。

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

考虑以下代码:

List<Foo> fooList = new List<Foo>();
List<IFoo> iFooList = fooList;    //Illegal
iFooList.Add(new SomeOtherFoo()); //That's not Foo!

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

将方法更改为IEnumerable<IFoo>,它将工作

请记住,泛型类型的专门化之间没有继承或实现关系。List<Foo>不以任何方式继承List<IFoo>。这就像比较stringint

这并不是说两种类型之间没有关系;只是我们讨论的关系不是继承。相反,我们在两个类型之间有一个专门化关系。. net 4.0及以后版本中的某些类型支持称为协方差的专门化属性。同变和反变允许泛型类型的专门化部分在某些情况下改变(注意这里的词根)。List<T>不是这些类型之一。

但是在这种情况下我要做的(我不知道你是否有。net 4.0)是使整个方法泛型:

public void MyMethod<T>(IEnumerable<T> items) where T : IFoo
{
    //...
}

注意,我也使用了IEnumerable<T>而不是List<T>。您应该仍然能够将列表传递给该函数,因为IEnumerable<T>List<T>之间存在继承/实现关系。您还可以处理数组和任何其他受支持的序列。IEnumerable也是支持协方差的类型之一。几乎任何需要List<T>参数的方法都应该更新为使用IEnumerable<T>

您需要创建一个新的List<IFoo>,并将第一个列表中的所有项目添加到其中

那么,你可以将它转换为新的列表声明为List<IFoo>,这是你需要的,像这样:

List<Foo> list = new List<Foo>();
theMethodThatTakesIFooList(list.ToList<IFoo>());

这将工作,我猜…

相关文章: