【问题标题】:Lambda Scope ClarificationLambda 范围说明
【发布时间】:2012-05-22 04:59:04
【问题描述】:

为什么我的参数x 的行为如此不稳定?

  1. 示例 1 - 当前上下文中不存在。
  2. 示例 2 - 无法重用 x,因为它是在“子”范围内定义的。
  3. 示例 3 - 很好。这是我感到困惑的部分。也许是不同的“子”范围?

示例 1

List<int> list = new List<int> { 1, 2, 3, 4, 5 };
var result = list.Where(x => x < 3);
Console.Write(result.ElementAt(x));

创建此编译时错误:

当前上下文中不存在名称“x”

我所期望的。

示例 2

List<int> list = new List<int> { 1, 2, 3, 4, 5 };
var result = list.Where(x => x < 3);
int x = 1;
Console.Write(result.ElementAt(x));

产生这个编译时错误:

不能在此范围内声明名为“x”的局部变量,因为它 会给'x'赋予不同的含义,它已经在a中使用过 'child' 范围来表示其他东西

我理解这个问题Is there a reason for C#'s reuse of the variable in a foreach? 中回答的范围界定。然而,这是我以前从未见过的。此外,它使What is the scope of a lambda variable in C#?这个问题的答案不完整或错误。

示例 3

List<int> list = new List<int> { 1, 2, 3, 4, 5 };
List<string> stringList = new List<string> { "A", "B" };
var result = list.Where(x => x < 3);
var result2 = stringList.Where(x => x != "A");

Console.Write(result2);

没有产生错误。


有了公认的答案,Eric Lippert 的这些博客文章帮助我了解正在发生的事情。如果有人仍然感到困惑:

declaration space

simple names

【问题讨论】:

标签: c# .net c#-4.0 lambda scope


【解决方案1】:

Example 1中,x定义在lamdba表达式的局部范围内,对第三行不可见

Example 2 中,现在您已经在同一个声明范围内声明了两个名为“x”的变量(可见性不同)

使用 lambda 或匿名方法,它“捕获”它正在运行的范围。如果您在与 lambda 定义相同的范围内有一个本地 x,那么它会“捕获”该 x 以将其拉入 lambda 可以访问的内容中——从而导致“x”的两个定义。您在 lambda 中声明的内容不会在另一个方向被捕获,因此它在 lambda 之外不可见。

Example 3 中,现在您没有使用仅在 lambda 之外的 lambda 本地变量,也没有在同一声明范围内命名相同的东西。

【讨论】:

  • 我还是不明白,示例 2 如何/为什么无法编译。如果 ex-2 不会,那么即使 ex-3 也不应该编译。根据我的逻辑,x "int x" 的第二个声明不应该与第一个有任何关系,因为它是明确定义的,并且仅适用于该行上定义的 lambda 表达式。这对我来说太新鲜太奇怪了。
  • @MrClan 看看this code 它类似于范围界定问题,它可以帮助您理解。
  • @MrClan 它无法编译,因为 "x => ..." 声明了一个 x 变量,而 "int x =1;"声明另一个。 lambda 是一个闭包,它可以引入在执行 lambda 时捕获的“外部变量”。为了捕获这些变量,它们需要是唯一的。 “x”可能意味着定义在 lambda 中的 x,或者定义在外部作用域中的 x——因此,编译器不知道在“x
【解决方案2】:

子范围(示例 3)可以使用相同的变量,但父子范围不能重新声明变量。

你可以使用 for:

// Child scopes
for (int i = 1; i < 10; i++){ /* do something */ }
for (int i = 1; i < 10; i++){ /* do something else */ }

这会失败:

// Child and parent
for (int i = 1; i < 10; i++){ /* do something */ }
int i = 33;

【讨论】:

    【解决方案3】:

    它并不像看起来那么复杂。

    如果为 lamda 表达式定义参数,则该参数仅在 lamda 表达式范围内有效

    (int x) =>
    {
       //x is only valid inside this scope
    }
    

    如果你有第二个变量,其定义在与 lamda 表达式相同的范围内,你会得到一个错误,因为这个第二个变量在 lamda 表达式的范围内也是有效的。

    void Foo()
    {
    
     int y;
    
     //y is valid in the scope of foo
    
     (int x) =>
     {
        //x is only valid inside this scope
        //y is valid in the scope of foo and the lamda expression
     }
    }
    

    在第三个示例中,您有 2 个不同的 lamda 表达式,因此有两个不同的范围

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-03
      • 2011-07-29
      • 1970-01-01
      • 2015-09-22
      • 2016-10-19
      • 1970-01-01
      相关资源
      最近更新 更多