Why doesn't C# allow me to use the same variable name in different scopes?
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.
Aren't these variables in different scopes, so I wouldn't be able to access the first matrix
from outside the if statement anyway?
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.
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.
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.)
This rule is documented in the C# 4.0 specification, section 7.6.2.1: Simple names, Invariant meaning in blocks.
(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?
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.
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/
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.
In fact, you can find this at 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.
Emphasis added.
And, from Section 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.
Emphasis added.
So, the thing is that while the scopes are different, the variable space is the same.
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.
上一篇: 局部变量范围错误