为什么要声明一个与父作用域中的变量同名的子变量? [英] Why can I declare a child variable with the same name as a variable in the parent scope?

查看:104
本文介绍了为什么要声明一个与父作用域中的变量同名的子变量?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最近写了一些代码,在该代码中我无意中将变量名重用为已在同名变量中的函数中声明的操作的参数.例如:

I wrote some code recently where I unintentionally reused a variable name as a parameter of an action declared within a function that already has a variable of the same name. For example:

var x = 1;
Action<int> myAction = (x) => { Console.WriteLine(x); };

当我发现重复项时,我很惊讶地看到代码可以完美地编译和运行,这不是基于我对C#范围的了解所期望的行为.一些快速的Google搜索出现SO问题,抱怨类似代码确实会产生错误,例如 Lambda范围澄清. (我将示例代码粘贴到我的IDE中,以确保它可以正常运行;它可以正常运行.)此外,当我在Visual Studio中进入重命名"对话框时,第一个x会突出显示为名称冲突.

When I spotted the duplication, I was surprised to see that the code compiled and ran perfectly, which is not behavior I would expect based on what I know about scope in C#. Some quick Googling turned up SO questions that complain that similar code does produce an error, such as Lambda Scope Clarification. (I pasted that sample code into my IDE to see if it would run, just to make sure; it runs perfectly.) Additionally, when I enter the Rename dialog in Visual Studio, the first x is highlighted as a name conflict.

为什么此代码有效?我在Visual Studio 2019中使用C#8.

Why does this code work? I'm using C# 8 with Visual Studio 2019.

推荐答案

为什么此代码有效?我在Visual Studio 2019中使用C#8.

Why does this code work? I'm using C# 8 with Visual Studio 2019.

您已经回答了自己的问题!这是因为您使用的是C#8.

You've answered your own question! It's because you're using C# 8.

从C#1到7的规则是:在同一个本地范围内,不能使用简单名称来表示两个不同的事物. (实际规则比这稍微复杂一些,但描述起来很繁琐;有关详细信息,请参见C#规范.)

The rule from C# 1 through 7 was: a simple name cannot be used to mean two different things in the same local scope. (The actual rule was slightly more complex than that but describing how is tedious; see the C# specification for details.)

此规则的目的是防止在您的示例中谈论的那种情况,在这种情况下,很容易混淆本地含义.特别是,此规则旨在防止出现诸如以下的混淆:

The intention of this rule was to prevent the sort of situation that you're talking about in your example, where it becomes very easy to be confused about the meaning of the local. In particular, this rule was designed to prevent confusions like:

class C 
{
  int x;
  void M()
  {
    x = 123;
    if (whatever)
    {
      int x = 356;
      ...

现在我们遇到一种情况,在M的内部,x表示this.x和本地x.

And now we have a situation where inside the body of M, x means both this.x and the local x.

尽管用心良苦,但此规则存在许多问题:

Though well-intentioned, there were a number of problems with this rule:

  • 未按规范实施.在某些情况下,可以将简单名称用作类型和属性,但是由于错误检测逻辑存在缺陷,因此并不总是将它们标记为错误. (请参见下文)
  • 错误消息的措词混乱,报告不一致.在这种情况下有多个不同的错误消息.他们前后一致地确定了罪犯;也就是说,有时会呼出 inner 用法,有时会呼出 outer ,有时只是令人困惑.
  • It was not implemented to spec. There were situations where a simple name could be used as, say, both a type and a property, but these were not always flagged as errors because the error detection logic was flawed. (See below)
  • The error messages were confusingly worded, and inconsistently reported. There were multiple different error messages for this situation. They inconsistently identified the offender; that is, sometimes the inner usage would be called out, sometimes the outer, and sometimes it was just confusing.

我在罗斯林重写中努力解决了这个问题;我添加了一些新的错误消息,并使旧消息在报告错误的位置上保持一致.但是,这种努力太少,为时已晚.

I made an effort in the Roslyn rewrite to sort this out; I added some new error messages, and made the old ones consistent regarding where the error was reported. However, this effort was too little, too late.

C#团队为C#8决定,整个规则引起的混乱比它应避免的多,并且该规则已从语言中退出. (感谢乔纳森·蔡斯(Jonathon Chase)确定何时退休.)

The C# team decided for C# 8 that the whole rule was causing more confusion than it was preventing, and the rule was retired from the language. (Thanks Jonathon Chase for determining when the retirement happened.)

如果您有兴趣了解此问题的历史以及我如何尝试解决此问题,请参阅我写的有关此问题的文章:

If you are interested to learn the history of this problem and how I attempted to fix it, see these articles I wrote about it:

https://ericlippert.com/2009/11/02/简单名称不是那么简单/

https://ericlippert .com/2009/11/05/simple-names-not-so-so-simple-part-two/

https://ericlippert .com/2014/09/25/confusing-errors-for-a-conusinging-feature-part-one/

https://ericlippert .com/2014/09/29/confusing-errors-for-a-conusinging-feature-part-two/

https://ericlippert .com/2014/10/03/confusing-errors-for-a-conusing-feature-part-three/

在第三部分的结尾,我注意到该功能与颜色颜色"功能之间也存在交互作用-即,该功能允许:

At the end of part three I noted that there was also an interaction between this feature and the "Color Color" feature -- that is, the feature that allows:

class C
{
  Color Color { get; set; }
  void M()
  {
    Color = Color.Red;
  }
}

在这里,我们使用了简单的名称Color来引用this.Color和枚举类型Color;根据对规范的严格阅读,这应该是一个错误,但是在这种情况下,规范是错误的,其意图是允许这样做,因为此代码是明确的,并且使开发人员进行更改会很烦人.

Here we have used the simple name Color to refer to both this.Color and the enumerated type Color; according to a strict reading of the specification this should be an error, but in this case the spec was wrong and the intention was to allow it, as this code is unambiguous and it would be vexing to make the developer change it.

我从来没有写过那篇文章来描述这两个规则之间所有奇怪的相互作用,所以现在这样做是没有意义的!

I never did write that article describing all the weird interactions between these two rules, and it would be a bit pointless to do so now!

这篇关于为什么要声明一个与父作用域中的变量同名的子变量?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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