返回IList< IList< T>祝辞
本文关键字:IList 祝辞 返回 lt | 更新日期: 2023-09-27 18:14:37
我有一个方法来构建列表的列表。我希望返回类型使用泛型的List<>接口,以减少与下游具体的List<>类型的耦合。但是,编译器很难处理类型转换。
public IList<IList<T>> Foo<T>()
{
return new List<List<T>>();
}
当这个工作时为什么会失败:
public IList<T> Foo<T>()
{
return new List<T>();
}
摆脱这种混乱的最优雅的方法是什么?
就这样做:
return new List<IList<T>>();
因为List<T>
实现了IList<T>
,所以您将能够在结果中添加任何类型的IList<T>
。例如:
Foo<int>().Add(new List<int>());
至于为什么,这是协方差/逆变的问题(我总是把这两个混淆)。基本上,如果您说您返回IList<IList<T>>
,那么有人应该能够将任何类型的IList<T>
添加到结果中:
Foo<int>().Add(new []{1}); // arrays implement `IList`
显然,如果您返回了List<List<T>>
,那么上面的代码行将不起作用:您将尝试将T[]
添加到List<T>
的集合中。因此,即使List<T>
是IList<T>
, List<List<T>>
也不是IList<IList<T>>
。
注意:下一部分只适用于。net 4及更高版本,因为这是第一个在接口中支持协方差和逆变的版本。
另一方面,如果您知道消费您的结果的人不打算向列表添加任何内容,但只是试图遍历它,您可以将返回类型更改为IEnumerable<IList<T>>
,然后返回List<List<T>>
就完全可以了。为什么?因为IEnumerable<T>
接口是协变:
public interface IEnumerable<out T>
这个"out"告诉编译器这个接口将只具有返回与T
相关的值的方法(如GetEnumerator
),并且它不会有任何将与T
相关的东西作为参数的方法(如Add
)。
这与c#协方差和逆变有关。你可以在这里阅读更多。
要做interface of interface of T,你的接口必须同时标记为out T或in T。IEnumerable标记为out T