• 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页

  • 相关阅读:
    Oracle递归查询,Oracle START WITH……CONNECT BY查询
    jquery Ajax请求示例,jquery Ajax基本请求方法示例
    Jquery EasyUI Combotree和 EasyUI tree展开所有父节点和获取完整路径
    Jquery EasyUI Combotree根据选中的值展开所有父节点
    Jquery EasyUI Combotree 初始化赋值
    Jquery EasyUI Combotree只能选择叶子节点且叶子节点有多选框
    SpringBoot Mybatis整合(注解版),SpringBoot集成Mybatis(注解版)
    SpringBoot Druid整合,SpringBoot 集成Druid
    安卓TTS语音合成经验分享(科大讯飞语音+)集成
    delphi7的新生,参与分布式应用开发,调用RESTful API,Json的应用
  • 原文地址:https://www.cnblogs.com/grj1046/p/2849012.html
Copyright © 2020-2023  润新知