不能传递List到一个期望列表的方法,其中Foo: IFoo
本文关键字:IFoo Foo 列表 期望 方法 一个 其中 List 不能 | 更新日期: 2023-09-27 18:04:15
我有一个类Foo
实现IFoo
接口。我有一个以List<IFoo>
为参数的方法。然而,它不能从List<Foo>
转换到List<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>
。这就像比较string
和int
。
这并不是说两种类型之间没有关系;只是我们讨论的关系不是继承。相反,我们在两个类型之间有一个专门化关系。. 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>());
这将工作,我猜…