How is variable declaration of variables declared?

How is the following possible?

switch (param.ParameterType) { case Type x when x == typeof(byte): int invalid; break; case Type x when x == typeof(short): int invalid; break; case Type x when x == typeof(int): break; case Type x when x == typeof(long): break; } 

The question is how x is inside each case without visible blocks. Meanwhile, the invalid variable can be declared in different switching cases. It must be inside the block.

if there is no block, then after viewing the variables it will be impossible.

 { // case byte: Type x; int invalid; // break; // case short: Type x; // x can not be declared twice. int invalid; } 

if for each case there is an invisible block, then the following should be possible (but this is not so).

 { { // block for each case. // case byte: Type x; int invalid; // break; } { // case short: Type x; int invalid; // but this throws compile time error. } } 

It seems that the compiler is doing some kind of magic here, apparently x has a scope other than the invalid variable. Is this a mistake in the phase of semantic analysis of the compiler?

+5
source share
1 answer

The question is, how is x in each case without visible blocks. Meanwhile, an invalid variable cannot be declared in different switching cases. It must be inside the block.

Variables entered using pattern matching if labels have only the body area of ​​this case.

Variables entered "usually" in body bodies have the scope of the entire switch statement.

Yes, this is contradictory - but I would say that:

  • It is especially useful to be able to enter several variables with the same name using pattern matching
  • The scope of the variables introduced in the case expressions was a design error, and this simply prevents further error.

Note that you cannot declare the same variable multiple times using pattern matches for cases that use the same case block. For example, simplifying your code is fine:

 object o = null; switch (o) { case Type x when x == typeof(byte): break; case Type x when x == typeof(short): break; } 

But this is not so:

 object o = null; switch (o) { case Type x when x == typeof(byte): case Type x when x == typeof(short): break; } 

Perhaps the compiler may have some rules that allow you to enter several variables, if they are of the same type - this can be very convenient for general code. But it will definitely make the language even more complex ...


As an example of a design error point, the C # 5 specification really has an error because of it. The C # 5 specification (8.7.2) states:

The "no-skip" rule prevents a common class of errors that occur in C and C ++ when break statements are accidentally excluded. In addition, because of this rule, the switch sections of the operator statement can be arbitrarily rearranged without affecting the behavior of the operator.

This “arbitrary rearrangement” is in any case incorrect in C # 7 due to the pattern matching order, but has always been incorrect. Consider this code:

 class Test { static void Main(string[] args) { switch (args.Length) { case 0: string x; break; case 1: x = args[0]; break; } } } 

This is acceptable due to the odd rules for determining the scope - x is in scope and can be used in the "case 1" block. However, if you change the order of things:

 class Test { static void Main(string[] args) { switch (args.Length) { case 1: x = args[0]; // Invalid break; case 0: string x; break; } } } 

... now this gives a compile-time error. The variable is still in scope (the compiler knows what you mean by x ), but you cannot assign a value to a local variable before declaring it.

As far as I know, no one will ever want to use a variable declared in an earlier scope - it would be more reasonable to introduce a new variable declaration space for each block of the case, or for C #, requiring brackets for the block of the case anyway.

+8
source

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


All Articles