Chapter 2

 

Statements

 

C# provides us with a countless number of statements. Let us now understand each one of them in detail.

 

a.cs

public class zzz

{

public static void Main()

{

bool i = false;

if ( i)

int j = 40;

}

}

 

Compiler Errors

a.cs(7,1): error CS1023: Embedded statement cannot be a declaration or labeled statement

 

It is not mandatory for the if statement to have the {} if we want to limit its scope to only one line. However, we cannot have a variable declaration as the only line following it. This is because if the condition results to false, the variable will never be created.

 

 

The value of the variable i can only be determined at run time and thus C# flags an error. The line following the if condition, int j = 40;  is called an embedded statement.

 

Every C# statement has an end-point. The end-point is intuitively the end of the statement. If a statement can be executed, we call it a reachable statement else it is unreachable. Unreachable statements for some reason flag a warning and not an error. To figure out whether a statement is reachable or not, C# does flow analysis.

 

a.cs

public class zzz

{

public static void Main()

{

int i = 30;

const int j = 30;

if ( i == 3)

System.Console.WriteLine("hi");

if ( j == 3)

System.Console.WriteLine("hi");

}

}

 

Compiler Warning

a.cs(10,1): warning CS0162: Unreachable code detected

 

Two identical if statements. One produces unreachable code whereas the second does not. In the case of variable j, the compiler sees it as a const and therefore knows that its value will never change. The if will always end in false, therefore, a warning.

 

In the case of the first if, even though the value of variable i is 30 and C# knows that it results in false, it still believes that an act of God can change the value of variable i. Consequently, no error but a mere warning is generated

 

As for the value of a const variable, even God possesses no privilege to change it, hence the compiler pops up a warning. The above rule is part of what goes under the moniker of flow analysis. An end point should not be reached for a switch and a return statement.

The if statement falls under the set of selection statement. It executes statements depending upon the value of a controlling expression.

 

if (x) if (y) F(); else G();

 

if (x) {

            if (y) {

                        F();

            }

            else {

                        G();

            }

}

 

This block of if statements is copied straight from the documentation to denote an idea. The above two ifs are the same. What we want to highlight here is that the brackets are optional; the visual look and feel can get misleading at times.

 

Switch Statement

 

a.cs

public class zzz

{

public static void Main()

{

zzz a = new zzz();

a.abc(1);

a.abc(10);

}

void abc(int i)

{

switch (i)

{

case 0:

System.Console.WriteLine("zero");

break;

case 1:

System.Console.WriteLine("one");

break;

default:

System.Console.WriteLine("end");

break;

}

}

}

 

Output

one

end

 

A switch statement is a substitute to multiple ifs as both work in the same fashion. It is a matter of style in deciding on the use of them. We use the time of day to decide which statement to use when and where. In other words, alike if, the switch also brings intelligence to our programs.

 

The switch statement checks the value of the variable i against the values given with the case statement. If any one value matches, all the statements within the case upto the break statement are executed. If none of the case statements match, the default statement is executed. Remember it is not mandatory to have a default statement with a break. The value of the variable in question decides on the code to be executed.

 

a.cs

public class zzz

{

public static void Main()

{

}

void abc(int i)

{

switch (i)

{

case 0:

System.Console.WriteLine("zero");

case 1:

System.Console.WriteLine("one");

break;

}

}

}

 

Compiler Error

a.cs(8,1): error CS0163: Control cannot fall through from one case label ('case 0:') to another

 

The case statement has its own set of complex rules. The first one says that every case must end with a break statement; thereupon preventing it from encroaching into the next case. Don't we have railing to prevent us from falling over our balcony? Thus, there is no natural way invented to execute code within two case statements at the same time. Most people consider it to be an unnecessary restriction C# has placed on the usage of the case statement. Like everything in life, there is a workaround. But we will elaborate on that later.

 

a.cs

public class zzz

{

public static void Main()

{

zzz z = new zzz();

z.abc(0);

}

void abc(int i)

{

switch (i)

{

case 0:

System.Console.WriteLine("second");

goto case 1;

case 1:

System.Console.WriteLine("first");

break;

}

}

}

 

 

 

Output

second

first

 

We explained that one case could not fall through another case but if it is imperative then you can use the goto statement. This statement accepts a case statement as a parameter and then simply jumps to it. Thus, after executing the code of one case, we can jump to another case and execute its code.

 

a.cs

public class zzz

{

public static void Main()

{

zzz z = new zzz();

z.abc(0);

}

void abc(int i)

{

switch (i)

{

case 0:

System.Console.WriteLine("second");

goto case 1;

System.Console.WriteLine("hi");

case 1:

System.Console.WriteLine("first");

break;

}

}

}

 

Compiler Warning

a.cs(15,1): warning CS0162: Unreachable code detected

 

Output

second

first

 

Here we have confused the compiler to no end and we advise you not to write such code. At first, the compiler informs you that no lines of code after a goto will ever be called and thus generates an unreachable code warning.

 

But then the control seeps to the case statement directed by goto and forgets that it was falling through a case statement from another. We are not trying to belittle the compiler but can it not please remember goto statements that we write and stop looking stupid in front of our eyes.

 

a.cs

public class zzz

{

public static void Main()

{

zzz z = new zzz();

z.abc(0);

z.abc(3);

z.abc(1);

}

void abc(int i)

{

switch (i)

{

case 0:

System.Console.WriteLine("zero");

goto case 3;

case 1:

System.Console.WriteLine("one");

goto default;

case 3:

System.Console.WriteLine("two");

break;

default:

System.Console.WriteLine("last");

break;

}

}

}

 

Output

zero

two

two

one

last

 

To prevent a fall through, every case has to end either with a goto or a break. With a  break statement, no other code gets called but with a goto, the code to be executed depends entirely on the case it jumps to. The above code is the ideal way to write code. However…

 

a.cs

public class zzz

{

public static void Main()

{

}

void abc(int i)

{

switch (i)

{

case 0:

while ( true) ;

case 1:

return ;

case 3:

throw new System.Exception();

}

}

}

 

The documentation very clearly states that the end point of the case statement must not be reached. Thus, any lines of code that prevent the last line of the case being executed is legal tender. A while (true) goes on forever, This make sure that you do not leave the while forever and thus the endpoint of the case never gets reached. Though it does not make any sense at all as i being zero will enter the while and never leave the case.

 

A return is more logical at this point as it can exit the function altogether and not just the case. It may be what you had in mind, however. A throw statement also breaks the case, the try catch is not mandatory here. Just because the compiler does not complain with a warning or an error it does not mean that you are home scott free.

 

a.cs

public class zzz

{

public static void Main()

{

}

void abc(int i)

{

switch (i)

{

case 0:

System.Console.WriteLine("zero");

break;

case 0:

System.Console.WriteLine("one");

break;

}

}

}

 

Compiler Error

a.cs(13,6): error CS0152: The label 'case 0:' already occurs in this switch statement

 

Somebody somewhere did some research and found out that people fell asleep while writing code. When they woke up, they rewrote the same code again. Thus, we had two copies of the same case in the program. C# peeks into human mind and is aware that you'd fall asleep at the wheel.

 

Thus, it checks whether you are writing the same code all over again. If it catches you in the act, you will see an error like the one above. It makes no logical sense having two case statements with the same value. If the value of i happens to be zero then there is confusion as in which case should C# execute. The first, the second, or both, or, even better, none. Decisions, decisions, they are so difficult to make, so the C# compiler drops by an error.

 

a.cs

public class zzz

{

int j = 10;

public static void Main()

{

}

void abc(int i)

{

switch (i)

{

case j:

break;

case j > 4:

System.Console.WriteLine("zero");

break;

}

}

}

 

Compiler Error

a.cs(11,6): error CS0150: A constant value is expected

a.cs(13,6): error CS0029: Cannot implicitly convert type 'bool' to 'int'

 

Here we want to convince you that an if statement in our humble/esteem opinion is better than a switch statement. In a case statement, we have to check the variable with a constant value. We are not permitted to use a variable or a logical condition. They have to be constant predefined values only. This limits our flexibility in writing complex conditions thereby preventing us from writing more abstract more intelligent code.

 

a.cs

public class zzz

{

public static void Main()

{

zzz z = new zzz();

z.abc(7);

z.abc(70);

}

void abc(int i)

{

switch (i > 8)

{

case 4 > 5:

System.Console.WriteLine("first");

break;

case 4 < 5:

System.Console.WriteLine("second");

break;

}

}

}

 

Output

first

second

 

We could not for the life of us figure out, why the above program works. So we added the following lines at the end of the second case statement ergo producing an error.

 

case 40 > 5:

System.Console.WriteLine("third");

break;

 

and we got the following error

 

Compiler Error

a.cs(19,6): error CS0152: The label 'case 1:' already occurs in this switch statement

 

z.abc(7) initializes i to 7, hence  the switch condition becomes false. The case may show logical operations but finally has either 1 or 0 standing for true or false. As the switch results in false, the first case is executed where case has a value of 0. In the second case, z.abc(70), the switch is true and thus the second case that evaluates to true gets called.

 

In one of the earlier examples, we demonstrated that a duplicate case value was not admissible. The error delivers the same message. In the above case, the compiler should take up the Hitlerian attitude and erase all our code; to punish us for writing such gibberish.

 

a.cs

public class zzz

{

public static void Main()

{

zzz z = new zzz();

yyy a = new yyy();

z.abc(a);

}

void abc(yyy i)

{

switch (i)

{

case 0:

System.Console.WriteLine("second");

break;

case 1:

System.Console.WriteLine("first");

break;

}

}

}

class yyy

{

}

 

Compiler Error

a.cs(11,9): error CS0151: A value of an integral type expected

 

The C# compiler informs us that a switch statement can only take certain integral types. To be more specific, it can take an sbyte, byte, short, ushort, int, uint, long, ulong, char, string, or an enum-type. C# realizes that the switch has received a yyy object and since it cannot convert a yyy into the above integral types, it reports an error.

 

a.cs

public class zzz

{

public static void Main()

{

zzz z = new zzz();

yyy a = new yyy();

z.abc(a);

}

void abc(yyy i)

{

switch (i)

{

case 0:

System.Console.WriteLine("second");

break;

case 1:

System.Console.WriteLine("first");

break;

}

}

}

class yyy

{

public static implicit operator int ( yyy a)

{

System.Console.WriteLine("operator");

return 1;

} }

 

Output

operator

first

 

The only way to eliminate the error is by overloading an int operator with class yyy. This will convert the yyy object into an int. As the function returns the resultant int as 1, the second case will be called. In a real life scenario, the return value depends upon some instance variable. Thus each time the switch statement will call the int operator to convert the yyy object into an int and then call the case statements depending on the resultant value.

 

a.cs

public class zzz

{

public static void Main()

{

zzz z = new zzz();

yyy a = new yyy();

z.abc(a);

}

void abc(yyy i)

{

switch (i)

{

case 0:

System.Console.WriteLine("second");

break;

case 1:

System.Console.WriteLine("first");

break;

}

}

}

class yyy

{

public static implicit operator int ( yyy a)

{

System.Console.WriteLine("operator");

return 1;

}

public static implicit operator byte ( yyy a)

{

System.Console.WriteLine("operator");

return 1;

}

}

 

Compiler Error

a.cs(11,9): error CS0151: A value of an integral type expected

 

We really got off the wrong side of our bed today. We therefore added two operators, one that converts a yyy to an int and the other that converts a yyy to a byte. As the case has no preferences of a byte over a int, it gets confused and does not know which operator to call. Since both are equally probable, it flags an error. The switch expression decides on the governing type of the statement.

There are many more rules to switch that sensibly state that there can be no two defaults in a switch. The end-point, that is, the end of the switch must never be reachable or else it will result in a compile time error.

 

a.cs

public class zzz

{

public static void Main()

{

zzz z = new zzz();

z.abc(2);

z.abc(3);

}

void abc(int i)

{

switch (i)

{

case 0:

System.Console.WriteLine("first");

break;

case 3:

case 2:

System.Console.WriteLine("second");

break;

}

}

}

 

Output

second

second

 

You can have many case statements bunched up together. There will be no errors if you do so. In the above switch, for the values 2 and 3, the same code is executed. Thus multiple labels are permitted in the switch. case 2: can be replaced by a default: and it would still result in the same answer. Though it is not a good programming style as removing the case 2: would not change the answer and default means none of the above. The order of the case statements is irrelevant to the final answer so changing the order doesn't change anything. For that matter, the default came first for all that C# cares.

 

The governing type of a switch can also be a string. The case statement values are however case sensitive. We can also use null as we are talking real objects here.

 

Within a case statement we can use declaration statements i.e. create variables etc.

 

a.cs

public class zzz

{

public static void Main()

{

zzz a = new zzz();

a.abc(0);

}

void abc(int i)

{

switch (i)

{

case 0:

int j= 7;

System.Console.WriteLine(j);

break;

}

}

}

 

Output

7

 

a.cs

public class zzz

{

public static void Main()

{

zzz a = new zzz();

a.abc(0);

}

void abc(int i)

{

switch (i)

{

int j= 7;

case 0:

int k= 7;

break;

case 1:

System.Console.WriteLine(k);

break;

}

}

}

 

Compiler Error

a.cs(12,1): error CS1523: The keyword case or default must precede code in switch block

 

For some reason, we are not allowed to create variables in the switch statement. Had we been allowed, then the variable would have scope in the entire switch. As we are allowed to create them only in a case, their scope is restricted to that case only. In the above program, remove the line int j = 7 and relish the error as seen below.

 

Compiler Error

a.cs(16,26): error CS0165: Use of unassigned local variable 'k'

 

Empty

 

A lot of life goes by without doing anything. As shown in one of the earlier examples, the while loop did absolutely nothing. Whenever a statement does nothing we call it an empty statement. Perfectly valid in C#. Execution of an empty statement simply transfers control to the statement's end point.

 

a.cs

public class zzz

{

public static void Main()

{

}

void abc(int i)

{

goto aa;

aa:

}

}

 

Compiler Error

a.cs(10,1): error CS1525: Invalid expression term '}'

a.cs(11,1): error CS1002: ; expected

 

We normally create labels at the end of a function so that all code can jump to the end if they so choose to. Here we have created a label aa on the last line of function abc. We get an error as C# demands at least one statement following the label.

 

C# demands a statement so we have no choice but to give it an empty statement. The best way to cut short an argument is by doing what C# wants and give it a statement, albeit, an empty one, one that does nothing.

 

a.cs

public class zzz  {

public static void Main()

{

}

void abc(int i)

{

goto aa;

aa: ;

}

}

 

Just by placing a semicolon, we bring a big smile on the C# virtual face. ;)

 

Loops

 

In all, we have four iterative statements, the for, foreach, while and the last kid on the block, the do while.

 

a.cs

public class zzz {

public static void Main() {

int i = 1;

do

{

System.Console.Write(i + " ");

i++;

} while ( i <= 3);

}

}

 

Output

1 2 3

 

Earlier we learnt about the differences between the for and the while and the scientific reasons behind choosing one of them. Now we add a twist and introduce the do while. This is identical to the while. There is just one and only one difference between them. Minor but could be life-threatening at times. In a while, the condition is evaluated at the beginning of the loop whereas in the case of the do while it is at the end.

 

a.cs

public class zzz {

public static void Main() {

int i = 1;

do

{

System.Console.Write(i + " ");

i++;

} while ( i <= 0);

i = 1;

while ( i <= 0 ) {

System.Console.Write(i + "...");

i++;

}

}

}

 

Output

1

In the do statement, the loop condition is checked at the end of the first iteration. Thus, the loop is executed at least once. In the above case, the condition i <= 0 is false at the outset as the variable i is given a value of 1. In spite of this, the do executes once, the condition is patently false and we quit out.

 

For the while, the condition is checked at the very beginning and thus as the condition is false, the code in the while is never called.

 

a.cs

public class zzz

{

public static void Main()

{

for ( int i = 1; i <= 10 ; i++)

System.Console.Write(i + "...");

System.Console.Write(i);

}

}

 

Compiler Error

a.cs(7,22): error CS0103: The name 'i' does not exist in the class or namespace 'zzz'

 

Any variable created in the for has a lifetime or scope within the embedded statements only. The variable i does not exist beyond the for statements.

 

a.cs

public class zzz

{

public static void Main()

{

for ( int i = 1; ; i++)

System.Console.Write(i + "...");

}

}

 

Please, please do not run the above program as it will never ever stop unless you Ctrl-C it. The for condition if present must result in a boolean. Having a numeric data type in between the two semi colons would raise the red flag for the compiler and result in an error. If the boolean expression is omitted, then C# assumes the value to be true by default. Hence the above code never ever stops.

 

a.cs

public class zzz

{

public static void Main()

{

int [] a = new int[3]{1,2,3};

foreach ( int i in a)

{

System.Console.Write(i + " ");

i = 10;

zzz.abc(ref i);

System.Console.WriteLine(i);

}

}

public static void abc(ref int j)

{

System.Console.Write("abc " + j + " ");

j = 100;

}

}

 

Compiler Error

a.cs(9,1): error CS1604: Cannot assign to 'i' because it is read-only

a.cs(10,13): error CS1605: Cannot pass 'i' as a ref or out argument because it is read-only

 

We are not allowed to change the iteration variable nor pass it as a ref or out parameter. We are doing both in the above program, hence the error.

 

Jump Statements

 

Jump statements transfer control to another part of our program. This transfer takes place come hell, hath or fury. In other words, the transfer is unconditional. We have exactly five conditional statements namely break, continue, goto, return and throw. The statements that a jump takes you to, is called the target of the jump.

 

The break statement was touched upon in the switch statement where it exits out of the case. It works in a similar fashion for a while, for, foreach and do while. It simply exits out of the looping construct it is befitted in.

 

a.cs

public class zzz

{

public static void Main()

{

break;

}

}

 

Compiler Error

a.cs(5,1): error CS0139: No enclosing loop out of which to break or continue

 

You cannot have a break statement by itself. It has to be placed within a case or a loop construct.

 

a.cs

public class zzz {

public static void Main() {

int i = 1, j = 1;

for ( i = 1; i<= 10 ; i++) {

if ( i == 3)

break;

for ( j = 1; j <= 10; j++)

{

System.Console.WriteLine(i + "." + j);

if ( j == 1)

break;

}

}

System.Console.WriteLine(i + " " + j);

}

}

Output

1.1

2.1

3 1

 

The number of breaks introduced in the program must be equal to the loops statements. As all of us are very particular about money and will never forget who we lent it to, similarly C# is very finicky about breaks and hates it hanging around in the program code.

 

The inner break makes sure that the inner for executes only once and not 10 times. It ends the loop each time the value of j reaches 1. The outer break lets us prematurely exit the outer for loop when the value of i is 3. As we love pairing up people, C# pairs up breaks with loops.

 

a.cs

public class zzz

{

public static void Main()

{

int i = 1, j = 1;

for ( i = 1; i<= 10 ; i++)

{

if ( i == 3)

break;

for ( j = 1; j <= 10; j++)

{

System.Console.WriteLine(i + "." + j);

if ( j == 1)

goto aa ;

}

}

aa:

System.Console.WriteLine(i + " " + j);

}

}

 

Output

1.1

1 1

There is no known way to quit out of nested breaks in this version of C#. You may have to wait till the next version and even then, no guarantees. The only alternative here is a goto statement; this we have shown in the above program. These days the goto statement has fallen in disrepute. No programmer worth his/her salt will admit in public that they have ever used the goto statement. Most respectable programming schools will refuse to teach it. Your programming mother will wash your mouth with soap if she finds out that you have been reading all about goto.

 

a.cs

public class zzz {

public static void Main() {

int i = 1;

for ( i = 1; i<= 10 ; i++)

{

try

{

System.Console.WriteLine("1 try");

            try

            {          

            System.Console.WriteLine("2 try");

            break;

            }

            finally

            {

            System.Console.WriteLine("2 finally");

            }

}

finally

{

System.Console.WriteLine("1 finally");

}

}

System.Console.WriteLine(i);

}

}

 

Output

1 try

2 try

2 finally

1 finally

1

 

The for loop starts and enters the first try, Here it comes across another try and then when least expected encounters a break. It would love to get out of the for statement but it stops to think for a while. The try statement has a finally clause. Hence before it exits the try, it executes the code in the finally. Now it remembers that there is one more try statement in the outstanding. This try also has a finally clause. Once the code in finally gets executed, C# exits from the for loop.

 

Thus, if the break is nested among 20 finally clauses, all of them will first get executed and only then will the break perform its task. Replace the break with a goto aa: statement and the above explanation will still hold true.

 

a.cs

public class zzz

{

public static void Main()

{

int i = 1;

for ( i = 1; i<= 10 ; i++)

{

goto aa;

}

{

aa:

System.Console.WriteLine(i);

}

}

}

 

Compiler Error

a.cs(8,1): error CS0159: No such label 'aa' within the scope of the goto statement

 

Compiler Warning

a.cs(11,1): warning CS0164: This label has not been referenced

 

You can never transfer control from one block to another block. The goto will allow you to leave a block but never let you enter another block. This results in the error shown above. The warning like every warning is at times best ignored.

 

a.cs

public class zzz

{

public static void Main()

{

goto aa;

{

aa:;

}

}

}

 

Compiler Error

a.cs(5,1): error CS0159: No such label 'aa' within the scope of the goto statement

 

Compiler Warning

a.cs(7,1): warning CS0162: Unreachable code detected

a.cs(7,1): warning CS0164: This label has not been referenced

 

The compiler is very picky about you not entering a block. For those who came in late, a block is nothing but valid C# code in open and close brackets { }. Remember, come heaven or earth, you cannot enter a block. Add the above to one more mysteries in life that has no rational answer.

 

a.cs

public class zzz

{

public static void Main()

{

for ( int i = 1; i<= 10 ; i++)

{

try

{          

}

finally

{

break;

return ;

}

}

}

}

 

Compiler Error

a.cs(12,1): error CS0157: Control cannot leave the body of a finally clause

 

Compiler Warning

a.cs(13,1): warning CS0162: Unreachable code detected

 

Compiler Error

a.cs(13,1): error CS0157: Control cannot leave the body of a finally clause

 

You cannot quit out of a finally block with a break or return statement. If you have a short-lived memory, we will repeat and tell you that the finally clause of a try is always called. You cannot leave a finally abruptly. All code in finally must be executed.

 

We also heed to the warning that no code after a break ever is executed. In other words, the end point of a break will never be reached. If it does so, some people tell us that it signals the end of the world.

 

a.cs

public class zzz

{

public static void Main()

{

for ( int i = 1; i<= 3; i++)

{

System.Console.WriteLine("C" + i);

continue;

System.Console.WriteLine("A" + i);

}

}

}

Output

C1

C2

C3

 

The continue statement stops executing the balance statements and restarts a new iteration of the loop. It can be used in a while, do, foreach and obviously the for. The rules applied to break, like having a trillion of them, hold true here also. You can try the earlier programs of try and finally with continue in place of break.

 

Similar to break, you cannot place continue in a finally block. A break says bye-bye to a loop whereas a continue restarts from the first line of the for loop. Continue is used when for some unknown reason, the programmer doesn't want to quit the loop but wants to skip the remaining code in the loop.

 

It is then assumed that the code does not exist from the continue keyword to the end point of the loop and the control moves to the beginning of the loop. Identical to a break, if you ever write any code after continue, C# will not execute it for a million years. After that if the sun is yet left standing, it will then execute your code. Most of what has been repeated earlier also applies to the return keyword.

 

A goto abides by all rules of break and continue.

 

a.cs

public class zzz

{

public static void Main()

{

int aa = 10;

goto aa ;

aa: ;

}

}

 

C# stores the name of a label and the name of a variable in different sections of the program. As they belong to different namespaces, the above program does not generate any errors. Had C# stored the name of a function and name of a variable in a different namespaces, we could use the same name for both of them too.

 

A good programming language design looks at different namespaces it requires and the contents within them. The teeming millions like us then abide by their decision and pontificate on its merits and demerits. We however are powerless to change any of their decisions. The idea here is that you understand a little in English and then apply that knowledge to a large number of C# statements.

 

The checked and unchecked statements are similar to the corresponding operators except that these statements act on blocks. The lock statement applies to Threads.

 

The Other Odds and Ends

 

a.cs

class zzz

{

public static void Main()

{

aa: ;

aa: ;

}

}

 

Compiler Errors

a.cs(7,1): error CS0140: The label 'aa' is a duplicate

 

Nothing, read my lips, Nothing can ever be a duplicate. Not even a label.

 

a.cs

class zzz {

public static void Main()

{

goto case 5 ;

}

}

 

 

Compiler Errors

a.cs(5,1): error CS0153: A goto case is only valid inside a switch statement

 

A goto case statement only fits in a case statement. It cannot be used outside a case.

 

a.cs

class yyy

{

}

class zzz

{

public static void Main()

{

la:

;

{

la:

;

goto la;

}

}

}

 

Compiler Error

a.cs(13,1): error CS0158: The label 'la' shadows another label by the same name in a contained scope

 

Like variables, we cannot have two labels with the same name shadowing each other. If we use common sense then the goto would jump to the inner label. What makes sense to us is not what makes sense to the compiler. If we remove the goto statement, then the error too disappears.

 

a.cs

class zzz {

public static void Main()

{

if ( true) ;

}

}

Compiler Warning

a.cs(5,12): warning CS0642: Possible mistaken null statement

 

The compiler does not like nothingness. A semi colon by itself stands for a valid statement but at the same time is an empty statement. If we use a semi colon only where a statement is due, the compiler gently prods us with a warning.

 

a.cs

class zzz

{

public static void Main()

{

int i = 6;

switch(i)

{

}

}

}

 

Compiler Warning

a.cs(8,1): warning CS1522: Empty switch block

 

Empty vessels make the most noise. The compiler does not understand anything empty including a switch statement. Relax, it is only a warning and can be ignored!