zoukankan      html  css  js  c++  java
  • LINQ延迟查询

    11.1.4 推迟查询的执行

             在运行期间定义查询表达式时,查询就不会运行,查询会在迭代数据项时运行。

             比如说扩展方法Where()。它使用yield return语句返回谓词为true的元素。因为使用了yield return语句,所以编译器会创建一个枚举器,在访问枚举中的项后,就返回它们。

    public static IEnumerable<T> Where<T>(this IEnumerable<T> Source, Func<T, bool> predicate) {
        foreach(T item in Source) {
            if(predicate(item))
                yield return item;
        }
    }

      这是一个非常有趣也非常重要的结果。在下面的例子中,创建了String元素的一个集合,用名称arr填充它。接着定义一个查询,从集合中找出以字母J开头的所有名称。集合也应是排序好的。在定义查询时,不会进行迭代。相反,迭代在foreach语句中进行,在其中迭代所有的项。集合中只有一个元素Juan满足where表达式的要求,即以字母J开头。迭代完成后,将Juan写入控制台。之后在集合中添加4个新名称,再次进行迭代。

    var names = new List<string> {
        "Nino", "Alberto", "Juan", "Mike", "Phil"
    };
    var namesWithJ = from n in names
                     where n.StartsWith("J")
                     orderby n
                     select n;
    Console.WriteLine("First iteration");
    foreach(string name in namesWithJ) {
        Console.WriteLine(name);
    }
    Console.WriteLine();
    
    names.Add("John");
    names.Add("Jim");
    names.Add("Jack");
    names.Add("Denny");
    
    Console.WriteLine("Second iteration");
    foreach(string name in namesWithJ) {
        Console.WriteLine(name);
    }

    因为迭代在查询定义时不会进行,而是在执行每个foreach语句时进行,所以可以看到其中的变化,如应用程序的结果所示:

    First iteration
    Juan
    
    Second iteration
    Jack
    Jim
    John
    Juan

      当然,还必须注意,每次在迭代中使用查询时,都会调用扩展方法。在大多数情况下,这是非常有效的,因为我们可以检测出数据源中的变化。但是在一些情况下,这是不可行的。调用扩展方法ToArray()、ToEnumerable()、ToList()等可以改变这个操作,在示例中,ToList遍历集合,返回一个实现了Ilist<string>的集合。之后对返回的列表遍历两次,在两次迭代之间,数据源得到了新名称。

    var names = new List<string> {
        "Nino", "Alberto", "Juan", "Mike", "Phil"
    };
    var namesWithJ = (from n in names
                      where n.StartsWith("J")
                      orderby n
                      select n).ToList();
    Console.WriteLine("First iteration");
    foreach(string name in namesWithJ) {
        Console.WriteLine(name);
    }
    Console.WriteLine();
    
    names.Add("John");
    names.Add("Jim");
    names.Add("Jack");
    names.Add("Denny");
    
    Console.WriteLine("Second iteration");
    foreach(string name in namesWithJ) {
        Console.WriteLine(name);
    }

    在结果中可以看到,在两次迭代之间输出保持不变,但集合中的值改变了:

    First iteration
    Juan
    
    Second iteration
    Juan

    ——摘自 《C#高级编程(第七版)》 第189页

  • 相关阅读:
    [蓝桥杯2017初赛]青蛙跳杯子 BFS
    第十一章 进程和信号
    第七章 数据管理
    特殊符号大全
    第四章 Linux环境
    (十六)异常
    (十五)代理
    (十四)内部类
    第三章 文件操作
    (十三)对象克隆
  • 原文地址:https://www.cnblogs.com/grj1046/p/2849012.html
Copyright © 2011-2022 走看看