返回 IList<IList<T>>

13

我有一个方法,用于构建列表的列表。 我想使用通用的IList<>接口作为返回类型,以减少与具体的List<>类型的耦合。 但是,编译器在类型转换方面存在问题。

public IList<IList<T>> Foo<T>()
    {
        return new List<List<T>>();
    } 

为什么这个失败了,而这个却成功:

public IList<T> Foo<T>()
    {
        return new List<T>();
    } 

有什么最优雅的方法可以摆脱这个困境吗?


你使用的是哪个版本的.NET? - Oded
2个回答

22

只需要这样做:

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)。


小问题:LinkedList<>没有实现IList<> - phoog
谢谢你的建议。我现在正在构建一个IEnumerable<IList<T>>,并使用Linq .ToList()进行返回。 - Jason Suárez

1

这与C#的协变性和逆变性有关。您可以在此处阅读更多信息。

要对T的接口进行接口,您的接口必须都标记为out T或in T。IEnumerable被标记为out T。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接