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页

原文地址:https://www.cnblogs.com/grj1046/p/2849012.html