为什么 Lambda 变量作用域存在于 LINQ 查询之外

本文关键字:LINQ 查询 存在 Lambda 变量 作用域 为什么 | 更新日期: 2023-09-27 18:35:06

我读了这个问题(C#中lambda变量的作用域是什么?

但它是关于 LINQ Query 中的 Lambda 变量作用域。

现在回答我的问题

假设我有一个非常简单的 LINQ 查询。

var Foo = FoobBar.Select(x => x);
var x = somefunction();

编译器 说:A local variable 'x' cannot be declared in this scope because it would give a different meaning to 'x', which is already used in a 'child' scope to denote something else .

为什么会这样?当 LINQ 查询结束时,Lambda 变量不应该不复存在吗?

编辑:阅读答案后,我得出的结论是,它是外部x(从函数返回),其范围扩展到LINQ Query内部。

为什么 Lambda 变量作用域存在于 LINQ 查询之外

这与 LINQ 无关,而是与子作用域有关。

例如:

foreach (var bar in FooBar.Bars)
        {
            var x = FooBar.GetFoo();
        }
var x = new Foo();

从编译器生成完全相同的错误消息。

要解决这个问题,您只需将变量放在不同的(非嵌套)作用域中。例如:

foreach (var bar in FooBar.Bars)
        {
            var x = FooBar.GetBar();
        }
{
    var x = new Foo();
}

让我们仔细看看,

var Foo = FoobBar.Select(x => x);

true x 的范围在表达式中结束

var x = somefunction()

现在这很有趣,这也是包含 lamda 表达式的整个方法的范围,因此编译器无法区分,因为后者的范围与前者重叠。 并且信息量很大的消息也为"x"赋予了不同的含义,该含义已在"子"范围内使用(根据您的情况选择)

类似范围问题

也许您可以在另一个周围包含大括号,以便定义其范围

{
var x = somefunction()
}

想想如果 C# 允许这两个变量存在于同一个作用域级别,这将是不可能的:

static void test() {
    Action<int> x = (z) => {
        Console.WriteLine(z);               
    };

    int[] i = { 5,2,0,1,3,1,4 };
    var kyrie = i.Select (x => x);
}

你会如何对 C# 说你想将名为 x 的 Action 委托分配给 kyrie 变量;反之亦然,你会怎么对 C# 说你想使用整数投影本身?C# 将如何解决这个问题?

并且 C# 作用域解析非常一致,无论是在其他变量之前还是在其他变量之后声明它,它们都是相同的。 例如 http://www.anicehumble.com/2012/05/java-said-c-said-scope-consistency.html

为了消除这些方案的歧义,C# 不允许编译具有存在于同一级别的变量名称

的程序

这一切都是为了以明确的方式向编译器表达您的意图。C#在这方面做得很好

不清楚(对编译器来说)第二个"x"(在=>之后)指的是哪个"x"。

如果你写这个:

var Foo = FoobBar.Select(y => x);
var x = somefunction();

然后,lambda 中的x将与"某个函数"结果发生冲突。

不能在同一作用域中声明两个同名变量。

"相同范围"意味着它们都在当前范围内

void method()
{
    int a;
    int a; //wrong!
}

或者一个在当前范围内,另一个在子作用域中。

void method()
{
    int a;
    for(;;)
    {
        int a; //wrong again!
    }
}

这是设计使然,适用于从 int s 到 lambda 引用的任何变量。