在Linq中,Where
等扩展程序会返回IEnumerable
个集合,但OrderBy
之类的排序方法会返回IOrderedEnumerable
个集合。
因此,如果您的查询以OrderBy
结尾(即返回IOrderedEnumerable
),则以后不能附加Where
方法 - 编译器会抱怨类型为传递到Where
。
var query = Process.GetProcesses()
.Where(p => p.ProcessName.Length < 10)
.OrderBy(p => p.Id);
query = query.Where(p => p.ProcessName.Length < 5);
但是,如果你在一个查询中完成所有操作,那很好!
var query = Process.GetProcesses()
.Where(p => p.ProcessName.Length < 10)
.OrderBy(p => p.Id)
.Where(p => p.ProcessName.Length < 5);
我查看了Reflector中的程序集,看看编译器是否重新排序任何操作,但它似乎没有。这是如何工作的?
答案 0 :(得分:9)
IOrderedEnumerable<T>
扩展IEnumerable<T>
,因此您仍然可以使用任何扩展方法。你的第一段代码不起作用的原因是因为你有效地写了:
IOrderedEnumerable<Process> query = Process.GetProcesses()
.Where(p => p.ProcessName.Length < 10)
.OrderBy(p => p.Id);
// Fail: can't assign an IEnumerable<Process> into a variable
// of type IOrderedEnumerable<Process>
query = query.Where(p => p.ProcessName.Length < 5);
失败是因为query.Where(...)
只返回IEnumerable<Process>
,无法将其分配给query
变量。它没有调用Where
这就是问题 - 它将结果分配回原始变量。为了证明这一点,这段代码可以正常工作:
var query = Process.GetProcesses()
.Where(p => p.ProcessName.Length < 10)
.OrderBy(p => p.Id);
// Introduce a new variable instead of trying to reuse the previous one
var query2 = query.Where(p => p.ProcessName.Length < 5);
或者,您可以将查询声明为IEnumerable<T>
以开头:
IEnumerable<Process> query = Process.GetProcesses()
.Where(p => p.ProcessName.Length < 10)
.OrderBy(p => p.Id);
// Fine
query = query.Where(p => p.ProcessName.Length < 5);