为什么C#不允许我在不同的范围内使用相同的变量名?

时间:2022-04-10 16:45:08

Like for instance:

比如:

if ( this.IsValid )
{
    Matrix matrix = new Matrix();
}

Matrix matrix = new Matrix();

The compiler warns me saying:

编译器警告我说:

"A local variable named 'matrix' cannot be declared in this scope because it would give a different meaning to 'matrix', which is already used in a 'child' scope to denote something else.

“名为'matrix'的局部变量不能在此范围内声明,因为它会给'矩阵'赋予不同的含义,'矩阵'已在'子'范围内用于表示其他内容。

Aren't these variables in different scopes, so I wouldn't be able to access the first matrix from outside the if statement anyway?

这些变量不是在不同的范围内,所以我无法从if语句外部访问第一个矩阵吗?

5 个解决方案

#1


16  

UPDATE: The answer below from 2011 is correct for earlier versions of C#; in more recent versions, the rule described the answer has been removed from C#. The design team determined that the rule caused more confusion amongst developers leading to questions like this one than the buggy programs prevented would warrant, even after I greatly improved the error messages to more clearly diagnose the problem.

更新:2011年以下的答案对于早期版本的C#是正确的;在更新的版本中,规则描述的答案已从C#中删除。设计团队确定该规则引起了开发人员之间更多的混淆,导致出现类似这样的问题而不是有缺陷的程序可以保证,即使在我大大改进了错误消息以更清楚地诊断问题之后。


The answers given so far are very confusing. The correct analysis of the problem starts by reading the error message. The error message is telling you what is actually wrong:

到目前为止给出的答案非常令人困惑。通过阅读错误消息开始正确分析问题。错误消息告诉您实际上是错误的:

"A local variable named 'matrix' cannot be declared in this scope because it would give a different meaning to 'matrix', which is already used in a 'child' scope to denote something else.

“名为'matrix'的局部变量不能在此范围内声明,因为它会给'矩阵'赋予不同的含义,'矩阵'已在'子'范围内用于表示其他内容。

Read that carefully. It is telling you precisely which rule of C# is being violated, namely that you are not allowed to use the same name to refer to two different things in the same scope. (Actually, the error message is slightly wrong; it should say "local variable declaration space" where it says "scope", but that is pretty wordy.)

仔细阅读。它正在告诉您C#的哪个规则被违反,即不允许您使用相同的名称来引用同一范围内的两个不同的东西。 (实际上,错误信息有点错误;它应该说“局部变量声明空间”,它表示“范围”,但这是相当罗嗦的。)

This rule is documented in the C# 4.0 specification, section 7.6.2.1: Simple names, Invariant meaning in blocks.

此规则记录在C#4.0规范的第7.6.2.1节中:简单名称,块中的不变含义。

(It is also illegal to have two local variables of the same name in overlapping declaration spaces. The compiler could be reporting that error as well, but it reports the more general error in this case.)

(在重叠声明空间中有两个相同名称的局部变量也是非法的。编译器也可能报告该错误,但在这种情况下报告更一般的错误。)

Aren't these variables in different scopes, so I wouldn't be able to access the first matrix from outside the if statement anyway?

这些变量不是在不同的范围内,所以我无法从if语句外部访问第一个矩阵吗?

Yes. That statement is true but irrelevant. The error here is that the same simple name has been used to refer to two different things in the same local variable declaration space.

是。这种说法是真实的,但无关紧要。这里的错误是在同一个局部变量声明空间中使用相同的简单名称来引用两个不同的东西。

Consider this scenario:

考虑这种情况:

class C 
{
    int x;
    void M()
    {
        x = 10; // means "this.x"
        for(whatever)
        {
            int x = whatever;
        }
    }
 }

Same deal. The error here is that the simple name "x" was used in the outer declaration space to refer to this.x, and was used in the inner declaration space to mean "local variable". Using the same simple name to refer to two different things in the same declaration space -- remember, the inner declaration space is a part of the outer one -- is both confusing and dangerous, and is therefore illegal.

同样的交易。这里的错误是在外部声明空间中使用简单名称“x”来引用this.x,并在内部声明空间中用于表示“局部变量”。使用相同的简单名称在同一个声明空间中引用两个不同的东西 - 记住,内部声明空间是外部声明空间的一部分 - 既困惑又危险,因此是非法的。

It is confusing for obvious reasons; one has a reasonable expectation that a name will mean the same thing everywhere throughout the declaration space in which it is first used. It is dangerous because small code edits are prone to changing the meaning:

由于显而易见的原因令人困惑;一个人有一个合理的期望,一个名称在它首次使用的声明空间的任何地方都意味着相同的东西。这很危险,因为小代码编辑很容易改变含义:

class C 
{
    int x;
    void M()
    {
        int x;
        x = 10; // no longer means "this.x"
        for(whatever)
        {
            x = whatever;
        }
    }
 }

If the declaration spaces in which the simple names are first used are not overlapping then it is legal for the simple names to refer to different things:

如果首次使用简单名称的声明空间不重叠,那么简单名称引用不同的东西是合法的:

class C 
{
    int x;
    void M()
    {
        {
            x = 10; // means "this.x"
        }
        for(whatever)
        {
            int x = whatever; // Legal; now the 
        }
    }
 }

For more information, and an amusing story about fried food, see

欲了解更多信息,以及有关油炸食品的有趣故事,请参阅

http://blogs.msdn.com/b/ericlippert/archive/tags/simple+names/

#2


7  

It is my belief that this is done in order to avoid obscure mistakes or code that's hard to read.

我相信这样做是为了避免模糊的错误或难以阅读的代码。

Using the same name of variable between a method scope and a child scope can lead to code that's very hard to read, since the variable type and, worse, meaning, can change and the only hint to the reader will be type declaration keyword before the variable.

在方法范围和子范围之间使用相同的变量名称可能导致代码非常难以阅读,因为变量类型,更糟糕的是,意义可以改变,并且对读者的唯一提示将是类型声明关键字之前变量。

However, I can also tell you that the IL generated for methods by the C# compiler will stick all variable declarations at the top, so maybe this decision driver was to simplify the variable parsing tree for the compiler.

但是,我也可以告诉你,C#编译器为方法生成的IL会将所有变量声明都放在顶部,所以这个决策驱动程序可能是为了简化编译器的变量解析树。

In fact, you can find this at MSDN:

实际上,您可以在MSDN上找到它:

The scope of a name is the region of program text within which it is possible to refer to the entity declared by the name without qualification of the name. Scopes can be nested, and an inner scope may redeclare the meaning of a name from an outer scope. (This does not, however, remove the restriction imposed by Section 3.3 that within a nested block it is not possible to declare a local variable with the same name as a local variable in an enclosing block.) The name from the outer scope is then said to be hidden in the region of program text covered by the inner scope, and access to the outer name is only possible by qualifying the name.

名称的范围是程序文本的区域,在该区域内可以引用名称声明的实体而无需限定名称。范围可以嵌套,内部范围可以从外部范围重新声明名称的含义。 (但是,这不会消除第3.3节规定的限制,即在嵌套块中,不可能声明一个与封闭块中的局部变量同名的局部变量。)外部作用域的名称是据说隐藏在内部范围覆盖的程序文本区域中,只有通过限定名称才能访问外部名称。

Emphasis added.

And, from Section 3.3:

并且,从第3.3节:

Each block or switch-block creates a different declaration space for local variables and constants. Names are introduced into this declaration space through local-variable-declarations and local-constant-declarations. If a block is the body of an instance constructor, method, or operator declaration, or a get or set accessor for an indexer declaration, the parameters declared in such a declaration are members of the block's local variable declaration space. The local variable declaration space of a block includes any nested blocks. Thus, within a nested block it is not possible to declare a local variable with the same name as a local variable in an enclosing block.

每个块或开关块为局部变量和常量创建不同的声明空间。通过local-variable-declarations和local-constant-declarations将名称引入此声明空间。如果块是实例构造函数,方法或运算符声明的主体,或索引器声明的get或set访问器,则在此类声明中声明的参数是块的局部变量声明空间的成员。块的局部变量声明空间包括任何嵌套块。因此,在嵌套块中,不可能声明与封闭块中的局部变量同名的局部变量。

Emphasis added.

So, the thing is that while the scopes are different, the variable space is the same.

所以,问题是虽然范围不同,但可变空间是相同的。

#3


5  

You can always do this...

你总能这样做......

void YourMethod() 
{
    if ( this.IsValid ) 
    {    
        Matrix matrix = new Matrix();
    }

    {
        Matrix matrix = new Matrix(); 
    }
}

...Each set of braces {} allows you to nest another level of scope. The issue you are having is the fact that nested scopes include the scope of their parents. If you declare a siblng scope it will be able to resuse variables within the same parent. But as others have pointed out this may become confusing later.

...每组括号{}允许您嵌套另一个范围的范围。您遇到的问题是嵌套范围包括其父项的范围。如果声明siblng范围,它将能够在同一父级中重用变量。但正如其他人指出的那样,这可能会在以后变得混乱。

#4


2  

Imagine a human being trying to read this code.

想象一下,人类试图阅读这段代码。

From the point of view of another developer trying to read your code, can you see how confusing it would be to have two different variables with the same name? Even if they are representing the same thing, it's just too hard to deal with two things with the same name.

从另一个尝试阅读代码的开发人员的角度来看,你能看到两个不同的同名变量有多么混乱吗?即使他们代表同样的事情,也很难处理同名的两件事。

#5


1  

Matrix matrix = new Matrix();

if ( this.IsValid ) 
{
    Matrix matrix = new Matrix(); 
} 

Imagine it instead written like that, it is a bit more obvious I would think why this is not allowed since the second instance should obviously be considered a *. Not being able to access the outer variables within child scopes would be bad.

想象一下,它是这样写的,更明显我会想到为什么不允许这样做,因为第二个实例显然应该被视为冲突。无法访问子范围内的外部变量会很糟糕。

From MSDN "A: This is correct behavior, and is covered in section 3.7 of the language spec. It says, “The scope of a local variable declared in a local-variable-declaration (8.5.1) is the block in the which the declaration occurs”." ... "This behavior is inteded to make incorrect re-use of variable names (such as in a cut and paste) less likely." (http://blogs.msdn.com/b/csharpfaq/archive/2004/05/18/why-can-t-i-use-the-same-variable-as-an-inner-loop-does.aspx)

从MSDN“A:这是正确的行为,并在语言规范的3.7节中介绍。它说,”在local-variable-declaration(8.5.1)中声明的局部变量的范围是其中的块声明发生在“。” ......“这种行为意图不太可能重复使用变量名称(例如剪切和粘贴)。” (http://blogs.msdn.com/b/csharpfaq/archive/2004/05/18/why-can-t-i-use-the-same-variable-as-an-inner-loop-does.aspx)

#1


16  

UPDATE: The answer below from 2011 is correct for earlier versions of C#; in more recent versions, the rule described the answer has been removed from C#. The design team determined that the rule caused more confusion amongst developers leading to questions like this one than the buggy programs prevented would warrant, even after I greatly improved the error messages to more clearly diagnose the problem.

更新:2011年以下的答案对于早期版本的C#是正确的;在更新的版本中,规则描述的答案已从C#中删除。设计团队确定该规则引起了开发人员之间更多的混淆,导致出现类似这样的问题而不是有缺陷的程序可以保证,即使在我大大改进了错误消息以更清楚地诊断问题之后。


The answers given so far are very confusing. The correct analysis of the problem starts by reading the error message. The error message is telling you what is actually wrong:

到目前为止给出的答案非常令人困惑。通过阅读错误消息开始正确分析问题。错误消息告诉您实际上是错误的:

"A local variable named 'matrix' cannot be declared in this scope because it would give a different meaning to 'matrix', which is already used in a 'child' scope to denote something else.

“名为'matrix'的局部变量不能在此范围内声明,因为它会给'矩阵'赋予不同的含义,'矩阵'已在'子'范围内用于表示其他内容。

Read that carefully. It is telling you precisely which rule of C# is being violated, namely that you are not allowed to use the same name to refer to two different things in the same scope. (Actually, the error message is slightly wrong; it should say "local variable declaration space" where it says "scope", but that is pretty wordy.)

仔细阅读。它正在告诉您C#的哪个规则被违反,即不允许您使用相同的名称来引用同一范围内的两个不同的东西。 (实际上,错误信息有点错误;它应该说“局部变量声明空间”,它表示“范围”,但这是相当罗嗦的。)

This rule is documented in the C# 4.0 specification, section 7.6.2.1: Simple names, Invariant meaning in blocks.

此规则记录在C#4.0规范的第7.6.2.1节中:简单名称,块中的不变含义。

(It is also illegal to have two local variables of the same name in overlapping declaration spaces. The compiler could be reporting that error as well, but it reports the more general error in this case.)

(在重叠声明空间中有两个相同名称的局部变量也是非法的。编译器也可能报告该错误,但在这种情况下报告更一般的错误。)

Aren't these variables in different scopes, so I wouldn't be able to access the first matrix from outside the if statement anyway?

这些变量不是在不同的范围内,所以我无法从if语句外部访问第一个矩阵吗?

Yes. That statement is true but irrelevant. The error here is that the same simple name has been used to refer to two different things in the same local variable declaration space.

是。这种说法是真实的,但无关紧要。这里的错误是在同一个局部变量声明空间中使用相同的简单名称来引用两个不同的东西。

Consider this scenario:

考虑这种情况:

class C 
{
    int x;
    void M()
    {
        x = 10; // means "this.x"
        for(whatever)
        {
            int x = whatever;
        }
    }
 }

Same deal. The error here is that the simple name "x" was used in the outer declaration space to refer to this.x, and was used in the inner declaration space to mean "local variable". Using the same simple name to refer to two different things in the same declaration space -- remember, the inner declaration space is a part of the outer one -- is both confusing and dangerous, and is therefore illegal.

同样的交易。这里的错误是在外部声明空间中使用简单名称“x”来引用this.x,并在内部声明空间中用于表示“局部变量”。使用相同的简单名称在同一个声明空间中引用两个不同的东西 - 记住,内部声明空间是外部声明空间的一部分 - 既困惑又危险,因此是非法的。

It is confusing for obvious reasons; one has a reasonable expectation that a name will mean the same thing everywhere throughout the declaration space in which it is first used. It is dangerous because small code edits are prone to changing the meaning:

由于显而易见的原因令人困惑;一个人有一个合理的期望,一个名称在它首次使用的声明空间的任何地方都意味着相同的东西。这很危险,因为小代码编辑很容易改变含义:

class C 
{
    int x;
    void M()
    {
        int x;
        x = 10; // no longer means "this.x"
        for(whatever)
        {
            x = whatever;
        }
    }
 }

If the declaration spaces in which the simple names are first used are not overlapping then it is legal for the simple names to refer to different things:

如果首次使用简单名称的声明空间不重叠,那么简单名称引用不同的东西是合法的:

class C 
{
    int x;
    void M()
    {
        {
            x = 10; // means "this.x"
        }
        for(whatever)
        {
            int x = whatever; // Legal; now the 
        }
    }
 }

For more information, and an amusing story about fried food, see

欲了解更多信息,以及有关油炸食品的有趣故事,请参阅

http://blogs.msdn.com/b/ericlippert/archive/tags/simple+names/

#2


7  

It is my belief that this is done in order to avoid obscure mistakes or code that's hard to read.

我相信这样做是为了避免模糊的错误或难以阅读的代码。

Using the same name of variable between a method scope and a child scope can lead to code that's very hard to read, since the variable type and, worse, meaning, can change and the only hint to the reader will be type declaration keyword before the variable.

在方法范围和子范围之间使用相同的变量名称可能导致代码非常难以阅读,因为变量类型,更糟糕的是,意义可以改变,并且对读者的唯一提示将是类型声明关键字之前变量。

However, I can also tell you that the IL generated for methods by the C# compiler will stick all variable declarations at the top, so maybe this decision driver was to simplify the variable parsing tree for the compiler.

但是,我也可以告诉你,C#编译器为方法生成的IL会将所有变量声明都放在顶部,所以这个决策驱动程序可能是为了简化编译器的变量解析树。

In fact, you can find this at MSDN:

实际上,您可以在MSDN上找到它:

The scope of a name is the region of program text within which it is possible to refer to the entity declared by the name without qualification of the name. Scopes can be nested, and an inner scope may redeclare the meaning of a name from an outer scope. (This does not, however, remove the restriction imposed by Section 3.3 that within a nested block it is not possible to declare a local variable with the same name as a local variable in an enclosing block.) The name from the outer scope is then said to be hidden in the region of program text covered by the inner scope, and access to the outer name is only possible by qualifying the name.

名称的范围是程序文本的区域,在该区域内可以引用名称声明的实体而无需限定名称。范围可以嵌套,内部范围可以从外部范围重新声明名称的含义。 (但是,这不会消除第3.3节规定的限制,即在嵌套块中,不可能声明一个与封闭块中的局部变量同名的局部变量。)外部作用域的名称是据说隐藏在内部范围覆盖的程序文本区域中,只有通过限定名称才能访问外部名称。

Emphasis added.

And, from Section 3.3:

并且,从第3.3节:

Each block or switch-block creates a different declaration space for local variables and constants. Names are introduced into this declaration space through local-variable-declarations and local-constant-declarations. If a block is the body of an instance constructor, method, or operator declaration, or a get or set accessor for an indexer declaration, the parameters declared in such a declaration are members of the block's local variable declaration space. The local variable declaration space of a block includes any nested blocks. Thus, within a nested block it is not possible to declare a local variable with the same name as a local variable in an enclosing block.

每个块或开关块为局部变量和常量创建不同的声明空间。通过local-variable-declarations和local-constant-declarations将名称引入此声明空间。如果块是实例构造函数,方法或运算符声明的主体,或索引器声明的get或set访问器,则在此类声明中声明的参数是块的局部变量声明空间的成员。块的局部变量声明空间包括任何嵌套块。因此,在嵌套块中,不可能声明与封闭块中的局部变量同名的局部变量。

Emphasis added.

So, the thing is that while the scopes are different, the variable space is the same.

所以,问题是虽然范围不同,但可变空间是相同的。

#3


5  

You can always do this...

你总能这样做......

void YourMethod() 
{
    if ( this.IsValid ) 
    {    
        Matrix matrix = new Matrix();
    }

    {
        Matrix matrix = new Matrix(); 
    }
}

...Each set of braces {} allows you to nest another level of scope. The issue you are having is the fact that nested scopes include the scope of their parents. If you declare a siblng scope it will be able to resuse variables within the same parent. But as others have pointed out this may become confusing later.

...每组括号{}允许您嵌套另一个范围的范围。您遇到的问题是嵌套范围包括其父项的范围。如果声明siblng范围,它将能够在同一父级中重用变量。但正如其他人指出的那样,这可能会在以后变得混乱。

#4


2  

Imagine a human being trying to read this code.

想象一下,人类试图阅读这段代码。

From the point of view of another developer trying to read your code, can you see how confusing it would be to have two different variables with the same name? Even if they are representing the same thing, it's just too hard to deal with two things with the same name.

从另一个尝试阅读代码的开发人员的角度来看,你能看到两个不同的同名变量有多么混乱吗?即使他们代表同样的事情,也很难处理同名的两件事。

#5


1  

Matrix matrix = new Matrix();

if ( this.IsValid ) 
{
    Matrix matrix = new Matrix(); 
} 

Imagine it instead written like that, it is a bit more obvious I would think why this is not allowed since the second instance should obviously be considered a *. Not being able to access the outer variables within child scopes would be bad.

想象一下,它是这样写的,更明显我会想到为什么不允许这样做,因为第二个实例显然应该被视为冲突。无法访问子范围内的外部变量会很糟糕。

From MSDN "A: This is correct behavior, and is covered in section 3.7 of the language spec. It says, “The scope of a local variable declared in a local-variable-declaration (8.5.1) is the block in the which the declaration occurs”." ... "This behavior is inteded to make incorrect re-use of variable names (such as in a cut and paste) less likely." (http://blogs.msdn.com/b/csharpfaq/archive/2004/05/18/why-can-t-i-use-the-same-variable-as-an-inner-loop-does.aspx)

从MSDN“A:这是正确的行为,并在语言规范的3.7节中介绍。它说,”在local-variable-declaration(8.5.1)中声明的局部变量的范围是其中的块声明发生在“。” ......“这种行为意图不太可能重复使用变量名称(例如剪切和粘贴)。” (http://blogs.msdn.com/b/csharpfaq/archive/2004/05/18/why-can-t-i-use-the-same-variable-as-an-inner-loop-does.aspx)