从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(); }