5

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

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( ))

4

5 回答 5

10

Enumerable.Where 创建一个新的实例WhereListIterator

是的。

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

因为它允许延迟流式传输行为。Where如果其消费者只想要第一个或第二个条目,则不必过滤所有列表。这对于 LINQ 来说是正常的。

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

“性能和功能的损失”来自您的设计。过滤后就不需要List<Customer>了,因为对它做任何修改都是没有意义的。

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

此外,以这种方式实现它要容易得多。想象一下,你必须重写WhereIList哪个必须返回IList。它应该怎么做?返回原始列表的代理?您每次访问都会遭受巨大的性能损失。返回带有过滤项目的新列表?这和做的一样Where().ToList()。返回原始列表但删除了所有不匹配的项目?这就是RemoveAll为什么,为什么要另一种方法。

请记住,LINQ 尝试发挥功能,并尝试将对象视为不可变对象。

于 2012-07-29T16:17:31.023 回答
2

正如其他人指出的那样,您需要使用ToList将结果转换为List<T>.

原因是Where懒惰评估,所以Where并没有真正过滤数据。它所做的是创建一个IEnumerable根据需要过滤数据的方法。

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

ToList强制将结果转换为List<T>,这似乎是您想要的。

于 2012-07-29T16:16:41.643 回答
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
}
于 2012-07-29T16:13:24.990 回答
0

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

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

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

于 2012-07-29T16:36:15.457 回答
-1

试试这个:

public List<Customer> FilterCustomersByStatus(List<Customer> source, string status)
{
    return source.Where(c => c.Status == status).ToList();
}
于 2012-07-29T16:12:47.890 回答