zoukankan      html  css  js  c++  java
  • LINQ中的延迟执行

    1.前言

    在使用 LINQ 查询的过程中存在着两种查询方式,一种是立即执行,另一种是延迟执行。下面将主要讲解 LINQ 的特殊支持——延迟执行。

    2.延迟执行

    延迟执行意味着,他们不是在查询创建的时候执行,而是在使用 foreach 语句遍历的时候执行(换句话说,当 GetEnumerator 的 MoveNext 方法被调用时)。现在考虑下面这种查询的实现:

    static void Main(string[] args)
    {
        List<int> list = new List<int>();
        list.Add(1);
        IEnumerable<int> result =
            from item in list
            select item;
        list.Add(2);
        foreach(var item in result)
        {
            Console.WriteLine(item);
        }
        Console.ReadKey();
    }

    其输出结果为:

    1
    2

    可以发现,在定义了 LINQ 查询后再向 list 中添加新项 “2”,仍然可以在 froeach 语句中输出 ”2“, 这是因为直到f oreach 语句对 result 进行遍历时,LINQ查询才会执行,这便是 LINQ 的延迟执行。

    除了下面两种查询运算符,所有其他的运算符都是延迟执行的:

    • 返回单个元素或者标量值的查询运算符,如First、Count等。
    • 下面这些转换运算符:ToArray、ToList、ToDictionary、ToLookup。

    上面两种运算符会被立即执行,因为他们的返回值类型没有提供延迟执行的机制,比如下面的查询会被立即执行。

    int matches = list.Where(n => (n % 2) == 0).Count();     // 1

    将返回的集合对象分配给一个新变量时,实现的时直接执行,如下面的示例:

    static void Main(string[] args)
    {
        List<int> list = new List<int>() { 1, 2, 3, 4, 5 };
        IEnumerable<int> result =
            from item in list
            select item;
        List<int> newlist = list.ToList();
        list.Add(6);
        foreach (var item in newlist)
        {
            Console.Write(item + " ");
        }
        Console.ReadKey();
    }

    其输出结果如下所示,即使在 ToList 后更改 list 中的项,foreach 语句的执行结果依旧不变:

    1 2 3 4 5

    3.重复执行

    但是,延迟执行带来的一个影响是,当我们重复遍历查询结果时,查询会被重复执行,例如下面的示例:

    static void Main(string[] args)
    {
        var numbers = new List<int>() { 1, 2 };
        IEnumerable<int> query = numbers.Select(n => n * 10);   // Build query
        foreach (int n in query) Console.Write(n + " ");        // 10 20
        numbers.Clear();
        foreach (int n in query) Console.Write(n + " ");        // <nothing>
        Console.ReadKey();
    }

    显然之前的查询数据会被覆盖,当我们需要保留之前查询结果时,这显然是不满足要求的,这时候可以使用上文中提到的转换运算符 ToArray、ToList、ToDictionary、ToLookup 方法存储查询结果。

    4.变量捕获

    延迟执行还有一个不好的副作用。如果查询的lambda表达式引用了程序的局部变量时,查询会在执行时对变量进行捕获。这意味着,如果在查询定义之后改变了该变量的值,那么查询结果也会随之改变。

    IEnumerable<char> query = "How are you, friend.";
    foreach (char vowel in "aeiou")
        query = query.Where(c => c != vowel);
    foreach (char c in query) Console.Write(c); //How are yo, friend.

    结果 query 中只有"u"被过滤了,可以修改代码如下:

    IEnumerable<char> query = "How are you, friend.";
    foreach (char vowel in "aeiou")
    {
        char temp = vowel;
        query = query.Where(c => c != temp);
    }
    foreach (char c in query) Console.Write(c); //Hw r y, frnd.

    此时,才能实现对元音字母的过滤。

  • 相关阅读:
    使用 libevent 和 libev 提高网络应用性能
    An existing connection was forcibly closed by the remote host
    各种浏览器的兼容css
    vs输出窗口,显示build的时间
    sass
    网站设置404错误页
    List of content management systems
    css footer not displaying at the bottom of the page
    强制刷新css
    sp_executesql invalid object name
  • 原文地址:https://www.cnblogs.com/jizhiqiliao/p/9850178.html
Copyright © 2011-2022 走看看