Lambda捕获参数引起歧义

我碰到了一个非常奇怪的C#行为,如果有人能够向我解释,我会很高兴。

说,我有以下班级:

class Program
{
    static int len = 1;
    static void Main(string[] args)
    {
        Func<double, double> call = len => 1;
        len = 1; // error: 'len' conflicts with the declaration 'csutils.Program.len'
        Program.len = 1; // ok
    }
}

就我所知,在评论中,我在视野中有以下对象: len变量和call 。 在lambda里面,我有局部参数lenProgram.len变量。

但是,声明这样的lambda之后,我不能在Main方法的范围内再使用len变量。 我必须将其引用为Program.len或者将lambda重写为anyOtherNameBesidesLen => 1

为什么会发生? 这是正确的语言行为,还是我遇到了语言错误? 如果这是正确的行为,那么语言架构如何证明它是正确的? 为什么lambda捕获变量可以混淆lambda之外的代码?

编辑:亚历山德罗德安德里亚已经有相当不错的例子(他的评论中的数字1和2)。

编辑2:这个代码(等于我在开头写的那个)是非法的:

class Program
{
    static int len = 0;
    static void Main(string[] args)
    {
        {
            int len = 1;
        }
        int x = len;
    }
}

然而,尽管该代码具有完全相同的范围结构,但该代码完全合法:

class Other
{
    static int len = 0;
    class Nested
    {
        static void foo()
        {
            int len = 1;
        }
        static int x = len;
    }
}

据我所见,在这种情况下发出编译时错误是正确的,因为当相同符号len没有时,不允许在子作用域中使用len (即匿名函数(lambda)的参数)在相同的方法中使用限定范围内的资格(用于别的东西)。

但是,错误文本很混乱。

如果您更改为:

static int len = 1;
static void Main(string[] args)
{
    len = 1;
    Func<double, double> call = len => 1;  // error CS0136: A local variable named 'len' cannot be declared in this scope because it would give a different meaning to 'len', which is already used in a 'parent or current' scope to denote something else
}

错误文字比较好。


其他一些例子:

static int len = 1;
static void Main()
{
    var len = 3.14; // OK, can hide field

    Console.WriteLine(len); // OK, 'len' refers to local variable

    Console.WriteLine(Program.len); // OK, hidden field can still be accessed, with proper qualification
}

上面的例子表明,它是细隐藏与具有相同名称的本地变量(或方法参数)的字段,只要该字段总是与资格访问(一个后.成员访问运算符)。

static int len = 1;
static void Main()
{
    if (DateTime.Today.DayOfWeek == DayOfWeek.Saturday)
    {
        var len = 3.14;

        Console.WriteLine(len);
    }

    Console.WriteLine(len); // error CS0135: 'len' conflicts with the declaration 'csutils.Program.len'
}

这表明,它是不可能隐藏len当您尝试使用领域在儿童范围len父范围。 错误文本再一次可以被批评。

static int len = 1;
static void Main()
{
    Console.WriteLine(len);

    if (DateTime.Today.DayOfWeek == DayOfWeek.Saturday)
    {
        var len = 3.14;  // error CS0136: A local variable named 'len' cannot be declared in this scope because it would give a different meaning to 'len', which is already used in a 'parent or current' scope to denote something else

        Console.WriteLine(len);
    }
}

你看这个比喻。


当然,这些问题在此之前已经提到过很多次,例如为什么不能在嵌套的本地作用域中声明重复的变量名?


错误信息是错误的,它应该指向包含lambda的行。

正如你所说的“lambda内部,我有本地参数lenProgram.len变量”,问题是lambda参数的名称与变量len冲突。 所以问题只出现在lambda表达式中。 问题不在于你“不能在Main方法的范围内使用len变量”。 这是两者之间的冲突,完全没有代码可以再编译。

链接地址: http://www.djcxy.com/p/78273.html

上一篇: Lambda capture parameter provoking ambiguity

下一篇: Time complexity and insertion into std::list