【问题标题】:Use one variable in multiple chained LINQ queries在多个链接的 LINQ 查询中使用一个变量
【发布时间】:2014-04-17 15:31:08
【问题描述】:

在多个链式调用中使用单个 lambda 表达式变量是否公平?例如:

MyList.Where(i => i.ID > 20).OrderBy(i => i.Name);

那么Where() 中使用的i 是否与OrderBy() 中使用的i 保持独立,或者它们之间是否存在一些隐藏的副作用,因此我必须为每个变量使用不同的变量?另外,您的答案是否也适用于 VB.NET?

我问这个是因为我在稍微不同的上下文中读到,我不应该在 LINQ 查询中直接使用 foreach 变量,而是在循环内制作变量的本地副本。上面的代码中是否也隐藏了一些类似的效果?

【问题讨论】:

  • 你可以做到,但它是否会令人困惑和难以管理是另一个问题。关于foreach 变量的观点可能与闭包有关。
  • 这可能有详细信息How does it work in C#?

标签: c# vb.net linq lambda


【解决方案1】:

它们是完全独立的。实际上,每次你声明一个 lambda 时,你也声明了范围变量,它们是这个 labda 表达式的本地变量。所以Where(i => i.ID > 20)中的iOrderBy(i => i.Name)中的i完全不同。在第一种情况下,i 指的是MyList 的随机元素,然后i 指的是来自Where 子句的序列的随机元素,这将是@ 的所有元素的序列987654329@ 有一个ID>20

【讨论】:

    【解决方案2】:

    详细一点,这很好:

    MyList.Where(i => i.ID > 20).OrderBy(i => i.Name);
    

    这两个名为 i 的变量是完全独立的,只存在于它们各自的 lambda 表达式的上下文中。然而,这不是:

    int i = 0;
    MyList.Where(i => i.ID > 20).OrderBy(i => i.Name);
    

    现在,您的 lambda 表达式中的 i 与父范围中定义的 i 冲突。

    foreach 的问题与您的原始问题稍微有些微妙和相切。如果你有这个:

    foreach (var foo in fooList) 
    {
        var filteredList = MyList.Where(i => i.ID > foo.Id).OrderBy(i => i.Name);
    }
    

    这里的问题是因为 LINQ 使用 延迟 执行并引用循环变量 foo,因此它将创建一个包含 foo 的闭包。问题是,它没有复制 foo 它实际上有一个对变量的引用。因此,当您最终通过迭代执行您的 lambda 时,或者:

    var bar = filteredList.ToList();
    

    Where lambda 中的foo 的值将是foo 的值现在,而不是声明 lambda 时的值。所以foo 永远是fooList 的最后一项。复制变量解决了这个问题,因为现在它将关闭那个不同的变量(只存在于循环的一次迭代中)而不是循环变量。

    foreach (var foo in fooList) 
    {
        var copy = foo;
        var filteredList = MyList.Where(i => i.ID > copy.Id).OrderBy(i => i.Name);
    }
    

    【讨论】:

      【解决方案3】:

      Lambda 表达式基本上是一种编写匿名方法的较短方式。因此,您的 lambda 示例中的 i 与匿名方法中的参数相同。换句话说,它们是相互独立的,就像不同方法的参数相互独立一样。

      为了可读性,将i 更改为person 或类似的东西可能是值得的。例如。 MyList.Where(person => person.ID > 20).OrderBy(person => person.Name);

      关于foreach:在 Eric Lippert 的博客上阅读关于此上下文中的闭包:http://blogs.msdn.com/b/ericlippert/archive/2009/11/12/closing-over-the-loop-variable-considered-harmful.aspx

      摘录:

      因为 ()=>v 的意思是“返回变量 v 的当前值”,而不是“返回创建委托时返回的值 v”。闭包关闭变量,而不是值。当方法运行时,很明显最后分配给 v 的值是 120,所以它仍然具有那个值。

      【讨论】:

      • 我更喜欢这个。
      【解决方案4】:

      见:Variable Scope in Lambda Expression - MSDN

      在 lambda 表达式中引入的变量在 外部方法。

      因此,在您的情况下,您的Where 子句声明了i,它仅在Where 子句中可见,因此独立于OrderBy 子句中声明的那个。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-03-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多