The scope of a C # variable: "x" cannot be declared in this scope because it would give the value "x",

if(true) { string var = "VAR"; } string var = "New VAR!"; 

This will lead to:

Error 1 A local variable with the name "var" cannot be declared in this area because it will give a different value for "var", which is already used in the "child" area to mean something else.

Nothing destroys the earth, but is it simply wrong? The developer and the developer and I were interested in whether the first declaration should be in a different area, so the second declaration cannot interfere with the first declaration.

Why can't C # distinguish between two areas? Should the first IF region not completely separate from the rest of the method?

I cannot invoke var from outside the if, so the error message is incorrect because the first var does not matter in the second area.

+61
scope c #
Jan 12 '10 at 13:51
source share
3 answers

The problem here is pretty much good practice and prevents unintentional errors. Admittedly, the C # compiler can theoretically be designed so that there is no conflict between the areas. This, however, will have a lot of effort for a small gain, as I see it.

Note that if the var declaration in the parent scope was before the if statement, an unresolvable name conflict would occur. The compiler simply does not distinguish between the following two cases. The analysis is performed solely on the basis of volume, and not the order of declaration / use, as you seem to expect.

Theoretically acceptable (but still not valid for C #):

 if(true) { string var = "VAR"; } string var = "New VAR!"; 

and unacceptable (since it will hide the parent variable):

 string var = "New VAR!"; if(true) { string var = "VAR"; } 

both are handled in exactly the same way in terms of variables and areas.

Now, is there any real reason for this sequenario, why can't you just give one of the variables a different name? I assume (hopefully) that your actual variables are not called var , so I really don't see a problem in this. If you still intend to reuse the same variable name, just put them in the affinity area:

 if(true) { string var = "VAR"; } { string var = "New VAR!"; } 

However, although it is valid for the compiler, it can lead to some confusion when reading the code, so I recommend against it in almost any case.

+43
Jan 12
source share

Is it just wrong?

No, that’s not at all. This is the correct implementation of section 7.5.2.1 of the C # specification, "Simple Names, Values ​​of Invariants in Blocks".

The specification states:




For each case of a given identifier as a simple name in an expression or declarator within the local space of the declaration of variable variables of this event, each other occurrence of the same identifier as a simple name in an expression or declarator must refer to the same organization. This rule ensures that the name value is always the same within a given block, switch block, for-, foreach- or use-statement or anonymous function.




Why can't C # distinguish between two areas?

The question is meaningless; Obviously, the compiler is able to distinguish between two areas. If the compiler could not distinguish between the two areas, then how could an error occur? The error message states that there are two different scopes, so the ranges were differentiated!

If the first IF region cannot be completely separated from the rest of the method?

No, it should not. The area (and local variable declaration space) defined by the block operator as a result of the conditional statement is lexically part of the external block that defines the body of the method. Therefore, the rules on the contents of the external block are applied to the contents of the internal block.

I cannot call var from outside if, so the error message is incorrect because the first var is not related to the second area.

This is completely wrong. It is understandable that only because the local variable is no longer in scope does the external block contain no errors. The error message is correct.

The error here has nothing to do with the fact that the scope of any variable overlaps the scope of any other variable; the only thing that matters here is that you have a block - an external block - in which the same simple name is used to mean two completely different things. C # requires that a simple name has one value in the whole block that first uses it.

For example:

 class C { int x; void M() { int x = 123; } } 

This is completely legal; the outer x region overlaps the inner x region, but this is not an error. Mistake:

 class C { int x; void M() { Console.WriteLine(x); if (whatever) { int x = 123; } } } 

because now the simple name "x" means two different things inside the body of M - it means "this.x" and the local variable "x". This confuses developers and code developers when the same simple name means two completely different things in one block, so this is illegal.

We allow parallel blocks to contain the same simple name, used in two different ways; it is legal:

 class C { int x; void M() { if (whatever) { Console.WriteLine(x); } if (somethingelse) { int x = 123; } } } 

because now the only block that contains two inconsistent uses of x is the external block, and this block does not contain the direct use of "x", only indirectly .

+35
Jan 12 '10 at 17:18
source share

This is valid in C ++, but the source for many errors and sleepless nights. I think that the guys from C # decided that it was better to throw a warning / error, because in the vast majority of cases this is a mistake, and not something that the encoder really wants.

Here is an interesting discussion about in which parts of the specification this error occurs.

EDIT (some examples) -----

In C ++, the following is permissible (and it does not matter if the external declaration is before or after the internal region, it will be more interesting and error prone, if it is earlier).

 void foo(int a) { int count = 0; for(int i = 0; i < a; ++i) { int count *= i; } return count; } 

Now imagine that the function has several lines longer, and it would be easy not to notice the error. The compiler never complains (and not the old days, not sure about newer versions of C ++), and the function always returns 0.

The behavior is obviously a mistake, so it would be nice if the C ++ - lint program or the compiler pointed to this. If this is not a mistake, it is easy to get around it by simply renaming the internal variable.

To add insult to injury, I remember that GCC and VS6 had different opinions about where the in for counter variable belonged. One said that he belongs in appearance, and the other said no. Cross-platform code is a bit annoying. Let me give you another example to support row counting.

 for(int i = 0; i < 1000; ++i) { if(array[i] > 100) break; } printf("The first very large value in the array exists at %d\n", i); 

This code worked in VS6 IIRC and not in GCC. Anyway, C # cleared up a few things, which is good.

+11
Jan 12
source share



All Articles