返回 IList>

发布于 2024-12-16 02:17:54 字数 391 浏览 1 评论 0 原文

我有一个构建列表列表的方法。我想让返回类型使用通用 IList<>接口以减少与具体 List<> 的耦合类型下游。然而,编译器在类型转换方面遇到了困难。

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

当它有效时为什么会失败:

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

摆脱这种混乱的最优雅的方法是什么?

I have a method which builds lists of lists. I'd like to have the return type use the generic IList<> interface to reduce coupling with the concrete List<> type downstream. However, the compiler struggles with the type conversion.

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

Why does this fail when this works:

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

What's the most elegant way out of this mess?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

猫九 2024-12-23 02:17:54

只需这样做:

return new List<IList<T>>();

因为 List 实现了 IList,因此您将能够添加任何类型的 IList 到结果。例如:

Foo<int>().Add(new List<int>());

至于为什么,这是协方差/逆变的问题(我总是把两者混淆)。基本上,如果您您要返回一个 IList>,那么有人应该能够添加任何类型的 IList 结果:

Foo<int>().Add(new []{1}); // arrays implement `IList`

显然,如果您返回了 List> 那么上面的代码行将不起作用:您将尝试添加一个T[]List 的集合。因此,即使 ListIListList> 也不是 >IList>

注意:下一部分仅适用于 .NET 4 及更高版本,因为这是第一个支持接口协变和逆变的版本。

另一方面,如果您知道使用您的结果的人是不打算向列表中添加任何内容,而只是尝试迭代它,您可以将返回类型更改为 IEnumerable> 然后就可以了返回一个List>。为什么?因为 IEnumerable 接口是协变的:

public interface IEnumerable<out T>

“out”告诉编译器该接口将只具有返回相关值的方法T (如 GetEnumerator),并且它不会有任何将与 T 相关的内容作为参数的方法(如 Add )。

Just do this:

return new List<IList<T>>();

Because List<T> implements IList<T>, you will be able to add any kind of IList<T> to the result. For example:

Foo<int>().Add(new List<int>());

As to the why, this is a matter of covariance/contravariance (I always get the two mixed up). Basically, if you say you're returning an IList<IList<T>>, then someone should be able to add any kind of IList<T> to the result:

Foo<int>().Add(new []{1}); // arrays implement `IList`

Obviously if you had returned a List<List<T>> then the above line of code wouldn't work: you would be attempting to add a T[] to the collection of List<T>. So even though a List<T> is an IList<T>, a List<List<T>> is not an IList<IList<T>>.

Note: This next portion only applies to .NET 4 and up, as that was the first version to support covariance and contravariance in interfaces.

On the other hand, if you know that the person consuming your result isn't planning to add anything to the list, but is only trying to iterate across it, you could change your return type to IEnumerable<IList<T>> and then it would be perfectly fine to return a List<List<T>>. Why? Because the IEnumerable<T> interface is covariant:

public interface IEnumerable<out T>

That "out" tells the compiler that this interface will only have methods that return values related to T (like GetEnumerator), and it won't have any methods that take something related to T as a parameter (like Add).

若水般的淡然安静女子 2024-12-23 02:17:54

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

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

That is related to C# covariance and contravariance. You can read more here.

To do interface of interface of T, your interfaces must both be marked as either out T or in T. IEnumerable is marked as out T.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文