当前位置: 首页 > 编程语言 > C#

linq匿名方法中的局部变量作用域(闭包)分享

时间:2023-04-11 01:23:20 C#

linq匿名方法中的局部变量作用域(闭包)LinqQuery中声明的局部变量作用域是什么。我正在编写以下代码staticvoidEvaluate(){varlistNumbers=Enumerable.Range(1,10).Select(i=>i);诠释我=10;}编译器在第inti=10行标记了一个错误,指出无法在此范围内声明名为“i”的局部变量,因为它会给“i”赋予不同的含义,而“i”已在“子”范围中使用表示其他我无法理解为什么会发生此错误。我的理解是我将在第一行之后(在foreach循环中)超出范围。所以我可以再次声明。实际行为是在第一行之后(在foreach循环中)无法访问i,这是正确的。但我不能再声明了。这看起来很奇怪。编辑这是基于安德拉斯的回应的以下问题。很好的答案,但提出了进一步的问题。staticvoidEvaluate3(){varlistNumbers=Enumerable.Range(1,10).Select(i=>i);varlistNumbers1=Enumerable.Range(1,10).Select(i=>i);}基于函数的逻辑评估。Select(i=>i)和inti=10,两者都是函数块的局部变量,因此是一个复杂性错误。由于方法块中有两个i,函数Evaluate3不应编译,但它编译成功,没有任何警告/错误。问题,Evaluate和Evaluate3都不应该编译,或者两者都应该编译。这里要注意的关键事实是声明:inti;...从头到尾遍历封闭范围-而不仅仅是从声明的地方开始。在.Net中,局部变量的声明只是指示编译器在整个范围内保留该名称和局部变量。这意味着一旦声明,它已经为前后所有行保留。实际上,这意味着您实际上应该将Evaluate理解为:staticvoidEvaluate(){inti;varlistNumbers=Enumerable.Range(1,10).Select(i=>i);我=10;如果你相应地编写了你的??方法,你会发现编译器错误发生在lambda声明上——这是完全合理的。值得庆幸的是,从人类的角度来看,C#编译器足够聪明,可以认识到代码的顺序对我们很重要,并且它实际上会将编译器错误分配给第二个或后续声明中的任何源代码行;因此,为什么它发生在inti=10;在您的评估版本中。了解函数局部i的实际生命周期后,编译器是正确的:使用i会与之前在lambda中使用i发生冲突。您可以通过使用显式范围来避免这种情况:staticvoidEvaluate(){varlistNumbers=Enumerable.Range(1,10).Select(i=>i);{整数我=10;在Evaluate3的例子中,你只需要注意虽然两个lambda共享父函数作用域,但它们也有自己的作用域,并且声明声明的位置——这就是为什么它们不会相互干扰(它们在影响,兄弟范围)。顺便说一句,Evaluate和Evaluate3最终可以简化为:staticvoidEvaluate(){{inti;}诠释我;//事实上,这是我之前使用显式范围的第二种情况-即,在同一函数的不同范围内,我实际上在每个范围内都有不同的类型。就像我说的那样——我再也没有这样做过,而且有问题的代码不再存在:)从规范来看:在局部变量声明中声明的局部变量的范围是声明发生的块。在局部变量的局部变量声明符之前的文本位置引用局部变量是错误的。您的lambdai=>i在局部变量inti=10的范围内,即使它是预先声明的。由于您在声明它之前使用了i而不是抛出错误,因此编译器会帮助指出您已经使用i来引用其他内容并且此声明更改了它。编辑:更新后:在第一种情况下,你的第一个i被包裹在一个lambda中,但你的第二个i被包裹在整个Evaluate方法中,包括lambda-因此你得到了错误。在第二种情况下,你的第一个i包含在它的lambda中,而你的第二个i包含在它的lambda中——两个i都不在另一个范围内,所以没有错误。您的段落“基于......我的两个逻辑,是功能块的本地......”是不正确的-第一个i不是功能块的本地,而是lambda。以上就是C#学习教程分享的全部内容:linq匿名方法中的局部变量作用域(闭包)。如果对你有用,需要了解更多C#学习教程,希望大家多多关注---本文来自网络收藏,不代表立场,如涉及侵权,请指教点击右侧联系管理员删除。如需转载请注明出处: