为啥我不能将 List<List<Foo>> 传递给 IEnumerable<IEnumerable<Foo>>

Posted

技术标签:

【中文标题】为啥我不能将 List<List<Foo>> 传递给 IEnumerable<IEnumerable<Foo>>【英文标题】:Why can't I pass a List<List<Foo>> to an IEnumerable<IEnumerable<Foo>>为什么我不能将 List<List<Foo>> 传递给 IEnumerable<IEnumerable<Foo>> 【发布时间】:2012-01-25 10:09:59 【问题描述】:

此代码生成两个编译时错误:

private void DoSomething()

    List<List<Foo>> myFoos = GetFoos();

    UseFoos(myFoos);


private void UseFoos(IEnumerable<IEnumerable<Foo>>)



The best overloaded method match for 'NameSpace.Class.UseFoos(System.Collections.Generic.IEnumerable&lt;System.Collections.Generic.IEnumerable&lt;Foo&gt;&gt;)' has some invalid arguments

Argument 1: cannot convert from 'System.Collections.Generic.List&lt;System.Collections.Generic.List&lt;Foo&gt;&gt;' to 'System.Collections.Generic.IEnumerable&lt;System.Collections.Generic.IEnumerable&lt;Foo&gt;&gt;'

投射到IEnumberable&lt;List&lt;Foo&gt;&gt; 不是问题。强制转换失败类型的内部 List 组件有什么不同?

【问题讨论】:

你是 C# 4.0 之前的版本吗? ***.com/questions/1280332/… 和 ***.com/questions/730401/upcasting-and-generic-lists 可能是相关的,如果不是完全的欺骗。 您确定您使用的是 C# 4.0? @AakashM:正确我使用的是 3.5。 @AakashM 查看这些示例中的 3.5 解决方法;除非/直到我真的需要支持内部容器不是 List&lt;&gt; 之外的东西,我想我会通过的。实现都属于丑陋和明显性检查。 【参考方案1】:

编辑:我刚刚意识到我还没有真正回答如何解决这个限制的问题。幸运的是,这很容易:

UseFoos(myFoos.Cast<IEnumerable<Foo>>());

该代码在 C# 4 下编译良好(当您为 UseFoos 参数指定名称时),它为接口和委托引入了泛型协变和逆变

作为一个更简单的示例,这在 C# 4 中有效,但在 C# 3 中无效:

IEnumerable<string> strings = new List<string>();
IEnumerable<object> objects = strings;

请注意,即使在 C# 4 中,类也不是一成不变的,所以这不起作用:

// This won't work
List<string> strings = new List<string>();
List<object> objects = strings;

...即使是接口,也只有在安全的情况下才支持:

// This won't work either
IList<string> strings = new List<string>();
IList<object> objects = strings;

接口(或委托)必须声明类型参数本身的变化,因此如果您查看 .NET 4 documentation for IEnumerable&lt;T&gt;,您会看到它被声明为

public interface IEnumerable<out T>

其中out 声明了T 中的协方差。

Eric Lippert 在他的covariance and contravariance 博客类别中有更多关于此的

【讨论】:

以上是关于为啥我不能将 List<List<Foo>> 传递给 IEnumerable<IEnumerable<Foo>>的主要内容,如果未能解决你的问题,请参考以下文章

为啥 swipeActions 修饰符不能直接与 List 容器一起使用? #SwiftUI

为啥我的 List<Foo> 不能用 protobuf-net 序列化?

为啥 std::move 不能与 std::list 一起使用

为啥我在 List<List<T>> 中复制 List<T> 时存在依赖关系? [复制]

为啥我不能将自动实现的 getter 和 setter 与 List 一起使用? (统一,C#)

微信小程序为啥数组不能push