C # variable variable does not match?

C # is quite suitable for selecting variables. How is it possible that it accepts this code:

class Program { int x = 0; void foo() { int x = 0; x = 1; Console.WriteLine(x); } } 

If you ask me, this is a clear name conflict. However, the compiler (VS 2010) accepts it. Why?

+6
source share
7 answers

This is not a name conflict: in C #, local variables take precedence over instance variables with the same name because their scope is narrower.

When the compiler matches a name reference with a name declaration, it uses the narrowest scope matching declaration

For more information on this, see the Reference Matching documentation.

+12
source

The rules for hiding the C # name are pretty complicated. The language allows you to specify the case that you mentioned, but does not allow many such cases. Cm.

http://ericlippert.com/2009/11/02/simple-names-are-not-so-simple/

for some information on this complex subject.

To answer your specific question: the compiler could certainly detect this conflict. In fact, it detects this conflict:

 class P { int x; void M() { x = 123; // The author intends "this.x = 123;" int x = 0; } } 

An equivalent C ++ program would be legal C ++, because in C ++ a local variable falls into scope at the point of its declaration. In C #, a local variable is in scope throughout its block and uses it before its declaration is illegal. If you try to compile this program, you will get:

 error CS0844: Cannot use local variable 'x' before it is declared. The declaration of the local variable hides the field 'P.x'. 

See: a local declaration hides a field . The compiler knows this. So why in your case is it not a mistake to hide the field?

Suppose for an argument that this should be an error. If this is also a mistake?

 class B { protected int x; } class D : B { void M() { int x; } } 

Field x is a member of D through inheritance from B. So this should also be a mistake, right?

Now suppose you have this program from Foo Corporation:

 class B { } 

and this program released by Bar Corporation:

 class D : B { void M() { int x; } } 

It compiles. Now suppose Foo Corp updates its base class and sends you a new version:

 class B { protected int x; } 

Are you telling me that every derived class containing a local variable named x cannot compile now?

That would be terrible. We must allow local variables to shadow members.

And if we let the locals shade the members of the base classes, it would be weird not to let the locals obscure the members of the classes.

+18
source

This is normal.

In designers, I often use the same thing.

 public Person(string name) { this.name = name; } 

Otherwise, it would be impossible to declare method parameters, which are called as member variables.

+3
source

The C # 4.0 specification says that scope is hidden through nesting:

3.7.1.1 Hiding through nesting

A name hiding during nesting can occur as a result of nesting of namespaces or types in namespaces, as a result of nesting types inside classes or structures, and as a result of parameters and local variables. In the example

 class A { int i = 0; void F() { int i = 1; } void G() { i = 1; } } 

inside method F, the instance variable i is hidden by the local variable i, but in method G, I still refer to the instance variable.

When a name in the inner scope hides a name in the outer scope, it hides all overloaded occurrences of that name.

In the example

 class Outer { static void F(int i) {} static void F(string s) {} class Inner { void G() { F(1); // Invokes Outer.Inner.F F("Hello"); // Error } static void F(long l) {} } } 

calling F (1) calls F declared in Internal, because all external occurrences of F are hidden by the internal declaration. For the same reason, calling F ("Hello") results in a compile-time error.

+1
source

There is no name conflict. The compiler always accepts the nearest / smallest scope variable.

In this case, it is the variable x that you declare in foo . Each variable can be accessed in a certain way, so that the name conflict does not conflict.

If you want to access external x, you can use this.x

0
source

Since the rule is that if there is a conflict between a local variable and a class member, the local variable takes precedence.

0
source

This is not ambiguous, local will be the variable that is supposed to be used in your function. If you need to get a class variable this.x, resolve the name resolution.

0
source

Source: https://habr.com/ru/post/908718/


All Articles