Linq如何在IOrderedEnumerable方法之后使用IEnumerable方法?

时间:2009-10-13 09:22:22

标签: linq ienumerable iorderedenumerable

在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中的程序集,看看编译器是否重新排序任何操作,但它似乎没有。这是如何工作的?

1 个答案:

答案 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);