代码之家  ›  专栏  ›  技术社区  ›  Graham Clark

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

  •  2
  • Graham Clark  · 技术社区  · 15 年前

    在Linq中,扩展方法 Where 返回一 IEnumerable 集合,但排序方法如 OrderBy 返回一 IOrderedEnumerable 收集。

    因此,如果您有一个以 排序 (即返回 可拆卸 )以后不能附加 在哪里? 方法-编译器抱怨正在传入的类型 在哪里? .

    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 回复  |  直到 15 年前
        1
  •  8
  •   Jon Skeet    15 年前

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