基本上我有这种方法。
public List<Customer> FilterCustomersByStatus(List<Customer> source, string status)
{
return (List<Customer>)source.Where(c => c.Status == status);
}
我向我抛出了一个无法施放的错误:
无法将'WhereListIterator`1 [AppDataAcces.Customer]'类型的对象强制转换为'System.Collections.Generic.List`1 [AppDataAcces.Customer]'。
为什么......?由于底层类型是相同的,Enumerable.Where是否创建了WhereListIterator的新实例,如果是这样,为什么有人会这样做,因为这是不必要的性能和功能损失,因为我总是要创建一个新列表(.ToList( ))
答案 0 :(得分:10)
是Enumerable.Where创建
的新实例WhereListIterator
是
如果是这样,为什么有人会这样做
因为它允许延迟流式传输行为。如果消费者只想要第一个或第二个条目,Where
将不必过滤所有列表。这对LINQ来说是正常的。
因为这是不必要的性能和功能损失,因为我总是要创建一个新列表(.ToList())
“性能和功能的损失”来自您的设计。过滤后您不需要List<Customer>
,因为对它进行任何修改都没有意义。
更新:“为什么会这样实施”
因为它是在IEnumerable
上实施的,而不是IList
。因此它看起来像IEnumerable
,它像IEnumerable
一样嘎嘎作响。
此外,以这种方式实现它要容易得多。想象一下你必须在Where
上写IList
。哪个必须返回IList
。它该怎么办?在原始列表上返回代理?每次访问都会遭受巨大的性能损失。返回包含已过滤商品的新列表?这与做Where().ToList()
一样。返回原始列表但删除了所有不匹配的项目?这就是RemoveAll
的用途,为什么要制作另一种方法。
请记住,LINQ尝试播放功能,并尝试将对象视为不可变的。
答案 1 :(得分:2)
正如其他人所指出,您需要使用ToList
将结果转换为List<T>
。
原因是Where
被延迟评估,因此Where
它的作用是创建一个IEnumerable
,根据需要过滤数据。
懒惰评估有几个好处。它可能更快,允许Where
使用无限IEnumerable
秒等
ToList
强制将结果转换为List<T>
,这似乎就是您想要的。
答案 2 :(得分:0)
Where扩展名过滤并返回IEnumerable<TSource>
因此您需要调用.ToList()将其转换回来
public List<Customer> FilterCustomersByStatus(List<Customer> source, string status)
{
return source.Where(c => c.Status == status).ToList();//This will return a list of type customer
}
答案 3 :(得分:0)
IEnumerable和IList之间的区别在于,可枚举不包含任何数据,它包含一个iterator,当您请求新数据时它会通过数据(例如,使用foreach循环)。另一方面,列表是数据的副本。在您的情况下,要创建List,ToList()方法将遍历整个数据并将它们添加到List对象。
根据您计划的用途,两者都有优点和缺点。例如,如果您计划多次使用整个数据,则应该使用该列表,但如果您计划使用它一次或计划使用linq再次查询,则应该选择enumerable。 / p>
编辑: 问题的答案为什么返回类型Where WhereListIterator而不是List,这部分是因为Linq如何工作。例如,如果您在第一个之后有另一个Where或另一个Linq语句,则编译器将使用整个方法链创建单个查询,然后返回最终查询的迭代器。另一方面,如果第一个Where将返回一个List,它将导致链中的每个Linq方法分别对数据执行。
答案 4 :(得分:-1)
试试这个:
public List<Customer> FilterCustomersByStatus(List<Customer> source, string status)
{
return source.Where(c => c.Status == status).ToList();
}