LAMBDA参数与类字段在以后访问范围冲突的领域 [英] Lambda parameter conflicting with class field on accessing field in later scope

查看:319
本文介绍了LAMBDA参数与类字段在以后访问范围冲突的领域的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个微弱的想象力,当涉及到的名字,所以我经常发现自己重复使用在我的代码标识。这使我碰上这一特定问题



下面是一些示例代码:

 公共委托无效TestDelegate(INT测试); 

公共类测试
{
私人诠释试验;

私人无效的方法(INT AAA)
{
TestDelegate德尔=测试=> AAA ++;

测试++;
}

公共静态无效的主要()
{
}
}

下面是编译错误(由 ideone 输出):

  prog.cs(11,3):错误CS0135:'测试'在孩子块
声明冲突prog.cs(9,22)(与以前的错误符号的位置)
编译失败:1个错误,0警告

11号线包含测试++ ,9号线包含了拉姆达。



顺便说一句时,Visual Studio 2013提供了一个不同的错误:

 测试的声明冲突Namespace.Test.test 

在上线仅11增量出现的错误。



中的代码编译成功,如果我注释掉或者9号线(拉姆达)或11号线(增量)。



这问题是一个让我吃惊 - 我确信拉姆达参数名称可以使用本地方法变量名(这是由代码编译时我注释掉增量排序确认)仅发生冲突。此外,如何能在lambda参数可能影响增量,这是对外面的λ的范围是什么?



我不能让我解决这个头......究竟做了我做错了什么? ?什么做神秘的错误消息在这种情况下,意味着



所有伟大的答案后编辑:



所以我觉得我终于明白,我打破了规则。在C#规范它没有很好地措辞(7.6.2.1,见乔恩斯基特对报价的答案)。这是什么的应该的意思是一样的东西:



您可以的的使用相同的标识符,是指不同事物(实体)在同一个局部变量声明空间,如果违规的用途之一是位于可看到从那里另一个是(直接)的范围的范围(直接)位于



不是标准的标准措辞,但我希望你明白我的意思。这个规则应该允许这样的:

  {
int类型的;
}

{
int类型的;
}



因为无论是两个变量 A的作用域可以看到从对方的范围;



和禁止这样的:

  {
int类型的;
}

int类型的;

由于第二个变量声明看到从第一个变量的作用域



和禁止这样的:

 类测试
{
INT测试;

无效的方法()
{
{
INT测试;
}

测试++;
}
}



,因为该领域的增量可以看到从块的范围(它不是一个声明无所谓)。



看来,C#6改变了这一规则,特别是使得最后一个例子(和我原来的代码)合法的,但我真的不明白究竟怎么了。



请纠正我,如果我做的这些例子一些错误。


< DIV CLASS =h2_lin>解决方案

斯利拉姆Sakthivel的不幸downvoted答案是正确的。 C#有一个规则,这是我写的次数,这要求在整个块中的相同的简单名称的每一个使用具有相同的含义。



我同意错误消息非常混乱。我的确在罗斯林大量的工作,以确保此错误消息是罗斯林减少混乱,这可能是打水漂的工作。



您可以阅读我对这条规则的文章,而我所做的作品,提高了错误信息,在这里:



HTTP ://ericlippert.com/tag/simple-names/



(在底部开始,这些都是逆时间顺序排列)



乔恩和其他人正确指出,在C#6的预发布版本,你没有得到的错误代码。我相信,在我离开球队,更多的工作于这种错误情况下完成的,而且可能已经放宽到更加宽松。



的原则,一个名字必须只意味着一件事是一个很好的,但它是棘手的实施,棘手的解释,以及大量的源本网站的问题,所以可能是设计团队决定去与更易于解释和实施的规则。正是这样的规则是什么,我不知道;我还没来得及浏览罗斯林的源代码,看看代码的那部分已经随着时间的演变。



更新:我在罗斯林队探子告诉我,这是犯23891e,这将缩短搜索增色不少。 : - )



更新:规则是走了;看到乔恩的详情答案。


I've got a weak imagination when it comes to names, so I often find myself re-using identifiers in my code. This caused me to run into this specific problem.

Here's some example code:

public delegate void TestDelegate(int test);

public class Test
{
    private int test;

    private void method(int aaa)
    {
        TestDelegate del = test => aaa++;

        test++;
    }

    public static void Main()
    {
    }
}

Here are the compilation errors (output by ideone):

prog.cs(11,3): error CS0135: `test' conflicts with a declaration in a child block
prog.cs(9,22): (Location of the symbol related to previous error)
Compilation failed: 1 error(s), 0 warnings

Line 11 contains test++, line 9 contains the lambda.

Incidentally, Visual Studio 2013 gives a different error:

'test' conflicts with the declaration 'Namespace.Test.test'

The error occurs at the increment on line 11 only.

The code compiles successfully if I comment out either line 9 (the lambda) or line 11 (the increment).

This issue is a surprise to me - I was sure that lambda parameter names can conflict only with local method variable names (which is sort of confirmed by the code compiling when I comment out the increment). Also, how can the lambda parameter possibly affect the increment, which is right outside the lambda's scope?

I can't get my head around this... What exactly did I do wrong? And what do the cryptic error messages mean in this case?

EDIT after all the great answers:

So I think I finally understood the rule that I broke. It is not well-worded in the C# spec (7.6.2.1, see Jon Skeet's answer for the quote). What it was supposed to mean is something like:

You can not use the same identifier to refer to different things (entities) in the same "local variable declaration space" if one of the offending uses is (directly) located in a scope which can be "seen" from the scope where the other is (directly) located.

Not the standard's standard phrasing, but I hope you understood what I mean. This rule was supposed to allow this:

{
    int a;
}

{
    int a;
}

because neither of the scopes of the two variables a can be "seen" from the other's scope;

and disallow this:

{
    int a;
}

int a;

because the second variable declaration is "seen" from the first variable's scope

and disallow this:

class Test
{
    int test;

    void method()
    {
        {
            int test;
        }

        test++;
    }
}

because the increment of the field can be "seen" from the block's scope (it not being a declaration doesn't matter).

It seems that C#6 changed this rule, specifically making the last example (and my original code) legit, though I don't really understand how exactly.

Please correct me if I made some mistakes in these examples.

解决方案

The unfortunately downvoted answer of Sriram Sakthivel is correct. C# has a rule, which I have written about a number of times, which requires that every usage of the same simple name throughout a block to have the same meaning.

I agree that the error message is extremely confusing. I did extensive work in Roslyn to ensure that this error message was less confusing in Roslyn, work which may have been for naught.

You can read my articles about this rule, and the work I did to improve the error message, here:

http://ericlippert.com/tag/simple-names/

(Start at the bottom; these are in reverse-chronological order.)

Jon and others correctly note that in prerelease versions of C# 6, you don't get the error for your code. I believe that after I left the team, more work was done on this error condition, and likely it has been relaxed to be more lenient.

The principle of "one name must mean only one thing" is a good one, but it is tricky to implement, tricky to explain, and the source of a lot of questions on this site, so probably the design team decided to go with an easier-to-explain-and-implement rule. What exactly that rule is, I don't know; I have not yet had time to browse the Roslyn source code and see how that part of the code has evolved over time.

UPDATE: My spies in the Roslyn team inform me that it was commit 23891e, which will shorten the search considerably. :-)

UPDATE: The rule is gone for good; see Jon's answer for details.

这篇关于LAMBDA参数与类字段在以后访问范围冲突的领域的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆