Min*_*s97 21 c# lambda field class increment
在名称方面我的想象力很弱,所以我经常发现自己在代码中重用了标识符.这导致我遇到这个特定的问题.
这是一些示例代码:
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()
{
}
}
Run Code Online (Sandbox Code Playgroud)
以下是编译错误(由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
Run Code Online (Sandbox Code Playgroud)
第11 test++
行包含第9行包含lambda.
顺便说一下,Visual Studio 2013给出了不同的错误:
'test' conflicts with the declaration 'Namespace.Test.test'
Run Code Online (Sandbox Code Playgroud)
该错误仅在第11行的增量处发生.
如果我注释掉第9行(lambda)或第11行(增量),代码会成功编译.
这个问题让我感到惊讶 - 我确信lambda参数名称只能与本地方法变量名称冲突(当我注释掉增量时,代码编译会对此进行确认).另外,lambda参数如何可能影响增量,这正好在lambda的范围之外?
我无法理解这个......我究竟做错了什么?在这种情况下,神秘的错误消息意味着什么?
在所有伟大答案之后编辑:
所以我想我终于理解了我破坏的规则.它在C#规范中没有措辞(7.6.2.1,参见Jon Skeet对报价的回答).这应该是什么意思:
如果其中一个违规用途(直接)位于可以从另一个范围"看到"的范围内,则不能使用相同的标识符来引用同一"局部变量声明空间"中的不同事物(实体)是(直接)位于.
不是标准的标准措辞,但我希望你理解我的意思.这条规则应该允许这样:
{
int a;
}
{
int a;
}
Run Code Online (Sandbox Code Playgroud)
因为这两个变量的范围都不a
能从另一个范围"看到";
并且不允许这样:
{
int a;
}
int a;
Run Code Online (Sandbox Code Playgroud)
因为第二个变量声明是从第一个变量的范围"看到"的
并且不允许这样:
class Test
{
int test;
void method()
{
{
int test;
}
test++;
}
}
Run Code Online (Sandbox Code Playgroud)
因为可以从块的范围"看到"字段的增量(它不是声明无关紧要).
似乎C#6改变了这个规则,特别是使最后一个例子(和我的原始代码)合法,但我真的不明白究竟是怎么回事.
如果我在这些例子中犯了一些错误,请纠正我.
Sri*_*vel 13
Eric Lippert在博客上发表了关于这个简单名称并不是那么简单.
简单名称(没有完全限定名称)总是只代表一个代码块中的一个东西.如果违反它,将会出现CS0135编译器错误.
在你的方法中method
,test
是一个简单的名称,这意味着两件事.c#中不允许这样做.
如果您创建测试字段,则使用限定名称而不是简单名称,编译器错误将消失.
private void method(int aaa)
{
TestDelegate del = test => aaa++;
this.test++;
}
Run Code Online (Sandbox Code Playgroud)
或者,如果您在不同的块中进行测试字段访问,编译器将很乐意编译.
private void method(int aaa)
{
TestDelegate del = (int test) => aaa++;
{
test++;
}
}
Run Code Online (Sandbox Code Playgroud)
现在,对于相同的简单名称,您没有两个不同的含义test
.因为第二次测试住在不同的街区.
截至目前(2015年4月),这个答案是有效的.从C#6.0开始,事情发生了变化.这个规则已经消失了.有关详细信息,请参阅Jon的答案.
不幸的是,Sriram Sakthivel的回答是正确的.C#有一个规则,我已经写了很多次,这要求在整个块中使用相同的简单名称具有相同的含义.
我同意错误信息非常混乱.我在罗斯林做了大量的工作,以确保这个错误信息在Roslyn中不那么混乱,这可能是徒劳的.
您可以阅读我关于此规则的文章,以及我为改进错误消息所做的工作,此处:
http://ericlippert.com/tag/simple-names/
(从底部开始;这些是按时间顺序排列的.)
Jon和其他人正确地注意到在C#6的预发布版本中,您没有收到代码的错误.我相信在我离开团队之后,在这个错误条件下做了更多的工作,并且可能已经放宽了更宽松.
"一个名字必须只意味着一件事"的原则是一个好的原则,但实施起来很棘手,难以解释,并且在这个网站上有很多问题的来源,所以设计团队可能决定采用更容易解释和实施的规则.究竟是什么规则,我不知道; 我还没有时间浏览Roslyn源代码,看看代码的这一部分是如何随着时间的推移而演变的.
更新:我在Roslyn团队中的间谍告诉我它是23891e,这将大大缩短搜索范围.:-)
更新:规则已经过去了; 有关细节,请参阅Jon的答案.