从List 到IEnumerable 返回List 的转换无效,为什么?

所以基本上我有这个方法。

public List FilterCustomersByStatus(List source, string status) { return (List)source.Where(c => c.Status == status); } 

我抛出一个它无法投射的错误:

无法将类型为’WhereListIterator`1 [AppDataAcces.Customer]’的对象转换为’System.Collections.Generic.List`1 [AppDataAcces.Customer]’。

为什么…? 由于底层类型是相同的,Enumerable.Where是否创建了WhereListIterator的新实例,如果是这样,为什么有人会这样做,因为这是不必要的性能和function损失,因为我总是要创建一个新列表(.ToList( ))

是Enumerable.Where创建WhereListIterator的新实例

是。

如果是这样,为什么有人会这样做

因为它允许懒惰的流式传输行为。 如果消费者只想要第一次或第二次输入,那么将不必过滤所有列表。 这对LINQ来说是正常的。

因为那是不必要的性能和function损失,因为我总是要创建一个新的列表(.ToList())

“性能和function的损失”来自您的设计。 过滤后不需要List ,因为对它进行任何修改都没有意义。

更新:“为什么这样实现”因为它是在IEnumerable实现的,而不是IList 。 因此它看起来像IEnumerable ,它像IEnumerable一样IEnumerable

此外,以这种方式实现它要容易得多。 想象一下,你必须写一篇关于IList 。 哪个必须返回IList 。 它该怎么办? 在原始列表上返回代理? 您将在每次访问时遭受巨大的性能损失。 返回包含已过滤商品的新列表? 它与做Where().ToList() 。 返回原始列表但删除了所有不匹配的项目? 这就是RemoveAll的用途,为什么要制作另一种方法。

请记住,LINQ尝试播放function,并尝试将对象视为不可变的。

正如其他人所指出的,您需要使用ToList将结果转换为List

原因是懒惰地评估了Where ,所以Where没有真正过滤数据。 它的作用是创建一个IEnumerable ,根据需要过滤数据。

懒惰评估有几个好处。 它可能更快,它允许使用Where无限IEnumerable s等。

ToList强制将结果转换为List ,这似乎是你想要的。

Where扩展过滤并返回IEnumerable因此您需要调用.ToList()将其转换回来

 public List FilterCustomersByStatus(List source, string status) { return source.Where(c => c.Status == status).ToList();//This will return a list of type customer } 

IEnumerable和IList之间的区别在于,可枚举不包含任何数据,它包含一个迭代器 ,当您请求新数据时它会遍历数据(例如,使用foreach循环)。 另一方面,列表是数据的副本。 在您的情况下,要创建List,ToList()方法将遍历整个数据并将它们添加到List对象。

根据您的计划用途,两者都有优点和缺点。 例如,如果您计划多次使用整个数据,则应该使用列表,但如果您计划使用一次或计划使用linq再次查询,则应该选择enumerable。

编辑:为什么返回类型Where WhereListIterator而不是List的问题的答案,部分是因为Linq如何工作。 例如,如果您在第一个之后有另一个Where或另一个Linq语句,则编译器将使用整个方法链创建单个查询,然后返回最终查询的迭代器。 另一方面,如果第一个Where将返回一个List,它将导致链中的每个Linq方法分别对数据执行。

试试这个:

 public List FilterCustomersByStatus(List source, string status) { return source.Where(c => c.Status == status).ToList(); }