c sharp the nuts and bolts
TRANSCRIPT
-
8/11/2019 C Sharp the Nuts and Bolts
1/276
243884994.doc 1 od 276
C sharp The Nuts and Bolts
Contents
Authors
Introduction
1.Concepts Revisited
2.Statements
3.Enums
4.Types
5.Delegates and Events
6.Conversions - Implicit and Explicit
7.Operators
8.Nested Classes
http://vijaymukhi.com/documents/books/csadv/contents.htm -
8/11/2019 C Sharp the Nuts and Bolts
2/276
243884994.doc 2 od 276
9.Miscellaneous
10.Compiler Error Messages
Authors
Vijay Mukhi([email protected]) is one of the pioneers of the Indian Infotech Industry. For
years, he has been the first to teach the emerging technologies in India thus ensuring that
India always has people trained in technologies that the world requires. Vijay has written
over 80 books on computers and programming over the last eight years on subjects ranging
from C, C++ (The Odyssey Series) to Animation and Networking to Java to C#. His newly
released book 'C#-The Basics' has covered many aspects of C# programming language in the
most simplified form. Vijay abhors complexities and hence his books showcase the most
difficult concepts explained through small programs, thereby giving a good understanding.
Microsoft's .Net technologies is what Vijay is now focussing on and he aims at writing
volumes on it.
Sonal Mukhi([email protected]) is a freeance !ro"rammer havin" a #ides!read
e$!osure to com!uter techni%ues and an"ua"es. &ona has done "round'reakin" #ork on
various nternet echnoo"ies ike *ava+ ,ctive-+ er+ C/ and more. &he has co0authored a
fe# 'ooks on com!uter !ro"rammin" too.
ntroduction
This is our second book on C# so we have assumed that you have read our first book, 'C# -The Basics'. It contains a lot more on the C# language that we could not cover in the first
one.
We have read a lot on what Microsoft and others have written, and wherever we liked the
idea, we simply copied it. And because we have picked from so many places, there was just
no way we could mention each and every of them. If you like an idea in this volume, please
do the same. The objective is to spread the C# message!
People often tend to compare C# with Java. It is with reason, and there's nothing wrong in
doing so. All that we would like to say is that C# has everything of Java and more. But very
soon, you could well have Java or some other language that betters C#'s act.
Today, C# is king of the hill, but we don't know how long it will last. If and when the king is
dethroned, we will be there paying our respects to the new king. With a new book, of course.
We are basically teachers, and believe that a book is a simple extension of teaching. So in
our books, we go step-by-step and systematically because that is the way one teaches in
real-life.
Requirements
The software requirements to successfully run all the programs in this book are
Operating System - Windows 2000
-
8/11/2019 C Sharp the Nuts and Bolts
3/276
-
8/11/2019 C Sharp the Nuts and Bolts
4/276
243884994.doc 4 od 276
the entry point of the program. It is the fountainhead of all knowledge. Incidentally, the C
programming language also calls Main as its first function for all C-language programs.
We can have as many as four different ways to declare Main in our program. They are as
follows:
static void Main() {...}static int Main() {...}static void Main(string[] a) {...}static int Main(string[] args) {...}
The operating system calls Main and waits for it to return a value. This value denotes the
success or failure of the program.
Main can either return a number or result in no return value, that is, void. If it returns an
int, by convention, a value of zero means success and any other value indicates an error. No
international authority can standardize the error numbers, it largely depends on the
programmer himself.
Copy as a command takes two parameters; the source and destination files. Similarly, a C#
program can also accept command line parameters at runtime. The executable a.exe can be
entered as
>a one two three
a.csclass zzz{public static void Main(string[] a)
{int i;for ( i!; i" a.#ength; i$$)%&ste'.onsole.rite#ine(a[i]);}}
*utputonetwothree
one, two, three are called command line parameters. The program accepts them in an array
of strings. As the array is a parameter to the function, we are free to decide on its name.Every array has a member called Length, which tells us the size of the array. In our case, it
is three. Thus, a[0] will contain the first word one and not the name of the program, a[1] will
contain two and a[3] - three. Main now behaves like any other function. What we do next
with the command line arguments depends entirely upon us.
a.csclass zzz{public static void Main(string[] a){}
public static int Main(){}
-
8/11/2019 C Sharp the Nuts and Bolts
5/276
243884994.doc od 276
}o'piler +rrora.cs(,-!)/ error %!!01/ 2rogra' 3a.e4e3 has 'ore than one entr& point defined/3zzz.Main(string[])3a.cs(5-06)/ error %!!01/ 2rogra' 3a.e4e3 has 'ore than one entr& point defined/ 3zzz.Main()3
You can have one and only one function called Main in any C# program. Even though you
can call it with different parameters, with the name changing, Main as a function must be
given only once.
a.csclass zzz{public static void Main(int i){}}
o'piler arninga.cs(,-0)/ warning %!!7/ 3zzz.Main(int)3 has the wrong signature to be an entr& pointo'piler +rrorerror %8!!0/ 2rogra' 3a.e4e3 does not have an entr& point defined
Here, the compiler first displays a warning signaling us that Main has not been created with
the right parameters. The error, following the warning, proclaims that we have forgotten to
create a function called Main. The signature includes the return type only in special cases
as entry point.
a.cs
class zzz{public static long Main(){return !;}}o'piler arninga.cs(,-!)/ warning %!!7/ 3zzz.Main()3 has the wrong signature to be an entr& pointo'piler +rrorerror %8!!0/ 2rogra' 3a.e4e3 does not have an entr& point defined
The signature refers to the parameters given to the function plus the return value. Main in
the above program returns 'long', hence we see the error.
a.csclass zzz{public void Main(){}}
o'piler +rrorerror %8!!0/ 2rogra' 3a.e4e3 does not have an entr& point defined
-
8/11/2019 C Sharp the Nuts and Bolts
6/276
243884994.doc 6 od 276
The signature also includes modifiers like static etc. It just proves the importance of the
function Main and the way it has been defined.
a.csclass zzz {public static void Main()
{}}class &&&{public static void Main(){}}o'piler +rrora.cs(-0)/ error %!!01/ 2rogra' 3a.e4e3 has 'ore than one entr& point defined/ 3zzz.Main()3a.cs(7-0)/ error %!!01/ 2rogra' 3a.e4e3 has 'ore than one entr& point defined/ 3&&&.Main()3
The error proves the point that you cannot have two different classes, zzz and yyy,
containing Main. Only one occurrence of Main is allowed. You always have only one chance
of a lifetime. Ditto with Main.
a.csclass zzz{private static void Main(){%&ste'.onsole.rite#ine(9hell9);}}
*utputhell
The access modifiers are not included within the signature for Main. Even though Main is
made private, it is considered as an entry point function, hence hell gets displayed. This
function is unique and works as a special case.
a.cspublic static void Main() {%&ste'.onsole.rite#ine(9hell9);}
class zzz{}
o'piler +rrora.cs(0-08)/ error %0807/ +4pected class- delegate- enu'- interface- or struct
You cannot create a function outside a class or a structure. This rule has to be strictly
adhered to even for Main.
a.cspublic class zzz
{public static int Main(){
-
8/11/2019 C Sharp the Nuts and Bolts
7/276
243884994.doc 7 od 276
return;}}
o'piler +rrora.cs(8-0)/ error %!05/ :n obect of a t&pe convertible to 3int3 is re
-
8/11/2019 C Sharp the Nuts and Bolts
8/276
243884994.doc 8 od 276
a.cs(7-0)/ error %!0!,/ =he na'e 3i3 does not e4ist in the class or na'espace 3zzz3
A variable is visible from the position it is created to the first close bracket. As i has been
created within the inner brackets, it is not available to external code thereafter. Hence the
error.a.csclass zzz {public static void Main() {for ( int i!; i " 0!; i$$){}i 6!;}}
o'piler +rrora.cs(5-0)/ error %!0!,/ =he na'e 3i3 does not e4ist in the class or na'espace 3zzz3
The variable i has been created within the for statement; therefore it can be accessed only
within the brackets pertaining to for. The scope of i is limited to the for {}.
a.csclass zzz{void abc(){i 6;}public static void Main(){ }int i ;}
The compiler does not read a .cs program in one iteration. If it did so, then the above
program would have resulted in an error as the function abc refers to the variable i which
has not been created for the moment. In the first round, the C# compiler scans the entire
code. In another pass, it reads the code of abc. As the first pass had already brought i into
existence, it does not generate any error and compiles successfully. We can use a variable of
a class before it is declared/created provided the variable has been declared before the class
ends.a.csclass zzz
{void abc(){i 6;int i ;}public static void Main(){ }}
o'piler +rrora.cs(8-0)/ error %!0!,/ =he na'e 3i3 does not e4ist in the class or na'espace 3zzz3
What works for variables in a class does not apply to functions as well. Within abc, we, first,initialize i to 9 and on the next line we create it. The compiler is not aware of i's existence
-
8/11/2019 C Sharp the Nuts and Bolts
9/276
-
8/11/2019 C Sharp the Nuts and Bolts
10/276
243884994.doc 1 od 276
variable and value defined within zzz. i now plays two different roles with different scopes in
the same class.a.csclass zzz{public static void Main()
{int ( 0) ;%&ste'.onsole.rite#ine();}}
*utput0
The compiler gives no error as the variable j is being used on the same line of its creation. It
does not precede it. Had it been like in the previous example, an error would have been
generated. The compiler first reads the line, creates a variable called j, then initializes it to 1.
The () brackets gain precedence.
a.csclass zzz{public static void Main(){int 0 - i $$ ;%&ste'.onsole.rite#ine(i);}}
*utput
A comma works like a semi-colon. The compiler treats it as two different statements.
Exceptions
a.csclass zzz{public static void Main(){&&& a;
anew &&&();tr&{a.abc();%&ste'.onsole.rite#ine(9?&e9);}catch{%&ste'.onsole.rite#ine(9@n +4ception9);}}}class &&&{
public void abc(){
-
8/11/2019 C Sharp the Nuts and Bolts
11/276
243884994.doc 11 od 276
throw new %&ste'.+4ception();}}
*utput@n +4ception
When we call a function, we are not aware of the exceptions and the types of exceptions it
will throw. One way to eradicate this uncertainty is to catch all the exceptions. You can do
so by not specifying any Exception with catch. It is perfectly legal tender to unspecify the
name of the Exception we are trying to catch in the catch.
a.csclass zzz{public static void Main(){&&& a;
anew &&&();tr&{a.abc();%&ste'.onsole.rite#ine(9?&e9);}catch{%&ste'.onsole.rite#ine(9@n +4ception9);}catch (%&ste'.+4ception e){%&ste'.onsole.rite#ine(9@n +4ception9);}
}}class &&&{public void abc(){throw new %&ste'.+4ception();}}
o'piler +rrora.cs(05-0)/ error %0!01/ =r& state'ent alread& has an e'pt& catch blocA
The error message is self-explanatory. The C# compiler does not permit you to have a catchwith no Exceptions followed by a catch with an Exception. The reason being that the first
catch is more generic and it will catch all the Exceptions. This leaves no exceptions for the
second catch. Reverse the order of the catches and watch the error disappear.
a.csclass zzz{public static void Main(){&&& a;anew &&&();
tr&{a.abc();
-
8/11/2019 C Sharp the Nuts and Bolts
12/276
243884994.doc 12 od 276
%&ste'.onsole.rite#ine(9?&e9);}catch (444 e){%&ste'.onsole.rite#ine(9@n +4ception9 $ e.=o%tring());}}}class &&&{public void abc(){throw new 444();}}class 444 / %&ste'.+4ception{}
*utput
@n +4ception444/ :n e4ception of t&pe 444 was thrown. at &&&.abc() at zzz.Main()
An exception is a class derived from System.Exception. It is child's play to create an
exception. We can create hundreds of Exceptions, there is no certain limit to it. The reason
behind introducing Exceptions was to simplify the job of identifying errors. Earlier if our
function returned six different types of errors then the method would return six different
numbers. Now, using exceptions it will throw 6 different objects. All these objects are derived
from the System.Exception class.
In the program above, xxx is derived from System.Exception and contains no code. Functionabc throws an object that looks like xxx hence the catch traps an xxx object while calling
the function. The output is displayed using the ToString function of the object.
a.csclass zzz{public static void Main(){&&& a;anew &&&();tr&{
a.abc();%&ste'.onsole.rite#ine(9?&e9);}catch (%&ste'.+4ception e){%&ste'.onsole.rite#ine(9@n +4ception9 $ e.=o%tring());}catch (444 e){%&ste'.onsole.rite#ine(9@n +4ception9 $ e.=o%tring());}}}class &&&{public void abc()
-
8/11/2019 C Sharp the Nuts and Bolts
13/276
243884994.doc 13 od 276
{throw new 444();}}class 444 / %&ste'.+4ception{}
o'piler +rrora.cs(05-7)/ error %!05!/ : previous catch clause alread& catches all e4ceptions of this or a supert&pe (3%&ste'.+4ception3)
System.Exception catches all the exceptions. It is very similar to having a catch with no
Exceptions. It is advisable to make it the last catch in the series of catches as if it is the
first, it will catch all the exceptions leaving nothing for the other catches. The earlier
explanation holds true in this case too.
Exceptions are said to be a structured, type safe and a uniform way of error handling. All
modern programming languages support exceptions.a.csclass zzz{public static void Main(){&&& a;anew &&&();tr&{a.abc();%&ste'.onsole.rite#ine(9?&e9);}catch (%&ste'.+4ception e){%&ste'.onsole.rite#ine(9@n +4ception9 $ e.=o%tring());}finall&{%&ste'.onsole.rite#ine(9@n finall&9);}}}class &&&{public void abc(){
throw new %&ste'.+4ception();}}
*utput@n +4ception%&ste'.+4ception/ :n e4ception of t&pe %&ste'.+4ception was thrown. at &&&.abc() at zzz.Main()@n finall&
And if we comment out the throw statement.
*utput?&e@n finall&
-
8/11/2019 C Sharp the Nuts and Bolts
14/276
243884994.doc 14 od 276
Once an exception is thrown, control passes to the catch statements. The statements in try
following the function that causes an exception, are never executed. After executing the
catch code, the next executable statement is the one following the try-catch block.
Irrespective of an exception being thrown or not, the statements following the try catch
blocks are executed. The question here is 'What if we want some code to be called
irrespective of whether an exception occurred a not'. To do so, we simply place the code infinally. The code within this block unquestionably is executed. A finally will always be called
at the end.
a.csclass zzz{public static void Main(){int i 8B!;}}
o'piler *utputa.cs(8-6)/ error %!!!/ Civision b& constant zero
The C# compiler is very intelligent. It knows that a number cannot be divided by zero and
thus stops us in our tracks with an error.
a.csclass zzz {public static void Main(){int !;int i 8B;
}}
It is however not very smart and in the above case, an exception is generated at run time.
a.csclass zzz{public static void Main(){tr&{int !;
int i 8B;}catch ( %&ste'.+4ception e){%&ste'.onsole.rite#ine(9Di 9 $ e.=o%tring());}}}
*utputDi %&ste'.Civide?&Eero+4ception/ :tte'pted to divide b& zero. at zzz.Main()
All exceptions thrown at run time can be caught using try-catch. In this way, anyunforeseen application error can be caught at run time gracefully.
-
8/11/2019 C Sharp the Nuts and Bolts
15/276
-
8/11/2019 C Sharp the Nuts and Bolts
16/276
243884994.doc 16 od 276
In the program, abc does not throw any exception but pqr does. The catch that catches it is
the inner catch and not the outer catch. Hence, the outer catch is not called. Conversely, the
finally for both the trys is called, the order is from the inner to the outer resulting into
seeing bye before last. Finally waits for the try-catch to complete its task.
Namespaces
C# programs are organized using namespaces which provide an organizational system for
presenting programs. A source file is defined as a compilation unit. A C# program can
consist of one or more compilation units. When we try and compile a C# program, all
compilation units are compiled together and hence can depend on each other.
a.cspublic na'espace via&{}
o'piler +rrora.cs(0-7)/ error %0807/ +4pected class- delegate- enu'- interface- or struct
A namespace is explicitly public and we are not allowed to specify any access modifiers to it.
a.cspublic class zzz{public static void Main(string[] a){using %&ste';}}
o'piler +rrora.cs(8-1)/ error %0!!,/ %&nta4 error- 3(3 e4pecteda.cs(8-0,)/ error %0!5/ ) e4pected
The using directive can only be placed at the beginning of the program. It cannot be used
anywhere else. The scope of using is the current source file and it does not influence any
other programs included while compiling.
a.cspublic class zzz{
public static void Main(string[] a){}}na'espace n0{class &&&{}}na'espace n0{class &&{}}
-
8/11/2019 C Sharp the Nuts and Bolts
17/276
243884994.doc 17 od 276
Namespaces are open-ended, the net result here will be that the namespace n1 will contain
both classes -- yy and yyy. However, we cannot change the name of the second class to yyy
as we cannot have the same name in the same namespace.
a.csusing z a0.a.&&&;using z0 a0.a;public class zzz{public static void Main(string[] a){z b;z0.&&& c;}}na'espace a0.a{class &&& {}
}
Using nested namespaces can make our names too large. We are provided with some help in
the form of an alias in the using directive. In the program, we have created two aliases -- z
and z1. Wherever we write a1.a2.yyy, the full name of the class yyy, it can now be replaced
with z. z1 stands for only the namespace name and thus we have to specify the name of the
class. An alias is conceptually very simple. Wherever C# sees a z, it will blindly replace it by
a1.a2.yyy.
a.csusing z a0.a.&&&;public class zzz{public static void Main(string[] a){}}na'espace a0.a{class &&& {}}class z{}
o'piler +rrora.cs(0-1)/ error %!815/ Fa'espace 33 alread& contains an alias definition for 3z3
You cannot have a class name and an alias with similar names as this will confuse the
compiler. Hence the error.
a.csna'espace a0.a{using z a0.a.&&&;class &&& {}}na'espace a,{class ddd / z
-
8/11/2019 C Sharp the Nuts and Bolts
18/276
243884994.doc 18 od 276
{}}
o'piler +rrora.cs(7-0,)/ error %!5/ =he t&pe or na'espace na'e 3z3 could not be found (are &ou 'issing a
using directive or an asse'bl& referenceG)
The class zzz remains the same as before. An alias created in one namespace or compilation
unit is simply not available to another. The scope of z is only limited to namespace a1.a2.
a.csusing z a0.a.&&&;na'espace a0.a{class &&& {}}na'espace a,{
class ddd / z{}}
Here we do not get any namespace error as we have placed the alias in the global or default
namespace. It is available to all namespaces in this source file only.
a.csusing z a0.&&&;na'espace a,{class ddd / z{}}o'piler +rrora.cs(0-00)/ error %!5/ =he t&pe or na'espace na'e 3a03 could not be found (are &ou 'issing ausing directive or an asse'bl& referenceG)a.cs(0-00)/ error %!5/ =he t&pe or na'espace na'e 3a03 could not be found (are &ou 'issing ausing directive or an asse'bl& referenceG)
C# checks the namespace alias and tries to resolve it to a sensible entity. If the compiler
cannot resolve it, it gives an error. Here C# is not knowledgeable of a1.
a.csusing z a.a,;na'espace a.a,{}na'espace a,{using z a;class ddd / z.&&&{}}
o'piler +rrora.cs(7-08)/ error %!,/ =he t&pe or na'espace na'e 3&&&3 does not e4ist in the class orna'espace 3a3 (are &ou 'issing a using directive or an asse'bl& referenceG)
-
8/11/2019 C Sharp the Nuts and Bolts
19/276
243884994.doc 19 od 276
The namespace alias can be hidden by another namespace alias. Globally z is a2.a3 but
within the namespace a3 it is temporarily given a value of a2. Thus the error reads a2.yyy
and not a2.a3.yyy. If we comment the inner alias, the compiler evaluates z to be a2.a3.yyy.
a.csna'espace a.a,{}na'espace a,{using z a;using z0 a.a,;using z z.a,;}
o'piler +rrora.cs(7-0)/ error %!5/ =he t&pe or na'espace na'e 3z3 could not be found (are &ou 'issing ausing directive or an asse'bl& referenceG)
The above error comes in as C# interprets only one using at a time. This means that C#
turns a blind eye to the other using's. The order of usings is of no relevance. We cannot
incorporate an alias within another. All of them have to be self contained with no
dependencies.
a.csusing a;using a,;class zzz{public static void Main()
{aaa a;}}na'espace a{class aaa {}}na'espace a,{class aaa {}}
o'piler +rrora.cs(1-0)/ error %!0!/ 3aaa3 is an a'biguous reference
The reason we get an error is because in Main, aaa can either become a2.aaa or a3.aaa. As
both namespaces a2 and a3 have a class aaa, both match and hence the error.
Changing using a2 to using a3, will give us only warnings as duplicate usings are not
flagged as an error. The class aaa now becomes a3.aaa and there is no ambiguity.
a.csna'espace aa{na'espace bb
{class cc{}}
-
8/11/2019 C Sharp the Nuts and Bolts
20/276
243884994.doc 2 od 276
}na'espace aa.bb{class cc{}}o'piler +rrora.cs(0!-1)/ error %!0!0/ =he na'espace 3aa.bb3 alread& contains a definition for 3cc3
We cannot have a class cc in namespace aa.bb as it already exists within the namespace bb
under namespace aa. The namespaces are additive, so it finally becomes aa.bb. The fully
qualified name for the existing class cc is aa.bb.cc. Thus namespace aa.bb can be viewed as
a namespace aa containing a namespace bb.
Variables
Variables are always stored in memory as they represent a memory location. They cannot be
stored in your or my pockets. The name of a variable is always decided by consulting an
astrologer. This is because you always need someone to take the flak for your programs not
working, so why not blame it on a poor choice of variable names? Remember, in this book,
we decide names of variables, in your life let your loved ones decide!
Every human being has to have some properties associated with him or her. One of these
could be, say, weight. In the same way every variable has to have a data type associated with
it, that informs C# about the values that can be stored in it. C# is very finicky about what
you store in it, similar to people who are very finicky about the clothes they wear. The C#
compiler guarantees that the variable will never ever have a value other than what is
permitted by its data type. Big brother is always watching over your shoulder!
Variables in C# fall in two states, initially assigned and initially unassigned. An initially
assigned variable has a defined value, an initially unassigned variable does not. Complex
words but a simple explanation.
If you have been counting, C# has so far created seven types of variables for us. These are:
static, instance, array, parameter types like value, reference and output and finally local
variables. Let us learn something more about each one of them.
a.cspublic class zzz {public static int i0;
int i;b&te [] i,;void abc(int i- ref int i8- out int i5){int i1 ;i50!;}public static void Main(){}}
First, a quick recap. i1 is a static variable due to the keyword static. i2 is an instance
variable as it is created outside a function and i3[0] is an array element if we initialize thearray member using new. Parameters by default are passed by value like i4. Variables like i5
-
8/11/2019 C Sharp the Nuts and Bolts
21/276
243884994.doc 21 od 276
and i6 are ref and out respectively due to the modifiers. Also, as i7 is created within a
function, it is called a local variable.
A static variable is born at the time the class is loaded and is alive and kicking as long as
the program runs. A static variable is initially assigned which means that it gets the default
values of its data type.
All other variables created by themselves in a class are called instance variables. Aninstance variable comes to life only when an instance of that class is created using the
keyword new. The instance variable dies when there are no more references to the object. In
languages like C#, like in real life, we have no control over death. Thus, instance variables
die whenever C# feels that it has no use for them. The programmer is powerless to kill an
instance variable.
An instance variable is initially assigned which means that it gets the default values of its
data type. The above line was simple cut and paste from the above paragraph. The only
change made was that the word instance was replaced by static. Good writers can waste
many words writing gibberish. A structure is always created on the stack. Thus, an instance
variable created in a structure, has the same life-time as the structure. If the structure isinitially assigned so are the instance variables and vice versa.
Array members behave in the same way as instance members so we see no point in
explaining the same concept using different words and consuming more paper and cutting
more trees. We apologize but had to have the above explanation spread over at least three
lines without repeating ourselves.
A value parameter is assigned a value at the time of function invocation. The variable is alive
at the open brace { and dies at the close brace }. A reference variable unlike a value variable
does not create a new memory location. It simply stands for a reference to the original
object. It represents the original memory location of the object in the function invocation.
Within a structure, the keyword this is passed by reference. A reference variable has to be
assigned a value on invocation unlike the out parameter. The out parameter is similar to the
ref in many aspects. Both have the same value as the underlying variable. We cannot
initialize an out variable at the time of invocation but must initialize it at the time of exit.
Also, as it is initially unassigned, we cannot read its value in the function. The keyword 'this'
in the constructor of a struct is an out parameter.
A local variable is created at the open { and dies at the close }. A local variable is never
initialized and thus has no default value.
a.cspublic class zzz{public static void Main(){int i;%&ste'.onsole.rite#ine(i);}}
o'piler +rrora.cs(5-5)/ error %!058/ Hse of unassigned local variable 3i3
A local variable is initially unassigned.
-
8/11/2019 C Sharp the Nuts and Bolts
22/276
243884994.doc 22 od 276
a.cspublic class zzz{public static void Main(){i 0!;int i;}}
o'piler +rrora.cs(8-0)/ error %!0!,/ =he na'e 3i3 does not e4ist in the class or na'espace 3zzz3
We cannot refer to a variable before it is created and if we do so, the above error is reported.
Had i been an instance variable and created even after Main, it would not have resulted in
an error.
a.cspublic class zzz{public static void Main(){i 0!;}static int i;}o'piler arninga.cs(1-0)/ warning %!056/ =he private field 3zzz.i3 is never used
All that we get from C# is a benign warning saying that we are not using the variable i. From
the compiler vocabulary, initializing a variable is not similar to using a variable. At times,
the garbage collector responsible for the murder of variables may decide to terminate it
before the close } as it is not being referred to. This is perfectly legal in C#. Thus a variable
may die an earlier death, it is all at the mercy of the great C#.
As a repetition, static, instance and array members all have default values. For a reference
variable, the default value is null.
a.cspublic class zzz{public static void Main()
{%&ste'.onsole.rite#ine(9.9 $ i $ 9.9);}static &&& i;}class &&&{}o'piler arninga.cs(1-0)/ warning %!56/ Iield 3zzz.i3 is never assigned to- and will alwa&s have its defaultvalue null
*utput..
-
8/11/2019 C Sharp the Nuts and Bolts
23/276
243884994.doc 23 od 276
i is a variable of a reference type. The warning very clearly informs us that C# has detected a
variable i, which has not been initialized to any value hence it will be null. Null means no
value and cannot be displayed. Null is not even a space and hence the two dots have nothing
separating them.
Arrays
An array is also known as a data structure in formal computer science books. In our view, a
rose by any other name is perceived to smell as sweet no matter what name you call it by. An
array will normally contain more than one variable called the elements of the array. An
array element is accessed using a number in square brackets known by a more difficult
name -- a computed index. Unfortunately, all the members of an array must have the same
data type called the array type. The value we supply to the keyword new in square brackets
is the size of the array or as termed in the array world, a rank specifier.
In Book 1, we have seen only single-dimensional arrays or arrays of rank one. In case of
more than one index, we call it a multi-dimensional array. The array dimension isrepresented by a value, which must be larger than or equal to zero. This value is defined as
length and must be positive. It does not have a compile time value but receives a value at
run time.
a.csclass zzz{public static void Main(){int [] a;a new int[];}}
o'piler +rrora.cs(5-0)/ error %0875/ :rra& creation 'ust have arra& size or arra& initializer
During the act of creating an array, the size must be specified.
a.csclass zzz{public static void Main(){
int [] a;a new int[!];}}
It is valid or perfectly legal to give a size of 0. The array, however, has no practical value if
you do so.
a.csclass zzz {public static void Main(){int [] a;
a new int[0!];a[00] 0!;
-
8/11/2019 C Sharp the Nuts and Bolts
24/276
243884994.doc 24 od 276
}}*utput+4ception occurred/ %&ste'.@nde4*ut*fJange+4ception/ :n e4ception of t&pe%&ste'.@nde4*ut*fJange+4ception was thrown. at zzz.Main()
If you exceed the bounds of an array, you will not get any compile time error but
unfortunately you land up to a run time error. C#, in other words, is extremely concerned
about going beyond the scope of the array. The exception thrown can be caught by your
program.
Once an array has been created, its length cannot be altered any more. We are not allowed
to resize the dimensions. Everything is fixed.
a.csclass zzz
{public static void Main(){int [] a;a new int[0!];a new int[0];}}
The first array remains inaccessible in the program as array a has been redefined as one
element array. Once an array has been created it cannot be resized later.
All arrays are derived from System.Array, which is an abstract class.a.csclass zzz{public static void Main(){string [] a;a new string[0!];a[0] 6;}}
o'piler +rrora.cs(1-7)/ error %!!6/ annot i'plicitl& convert t&pe 3int3 to 3string3
The conversion rules applying to data types also apply to an array.
a.csclass zzz{public static void Main(){int [] a new int[,] {!--7};int [] b new int[] {!--7};int [] c {!--7};
}}
-
8/11/2019 C Sharp the Nuts and Bolts
25/276
243884994.doc 2 od 276
There are many ways to skin a cat. In the same way, we can initialize an array in different
ways. The array a has been initialized the long way where we have specified the keyword new
with the size of the array along with the initial values in {} braces. In the case of b, we've
skipped the length and directly supplied three values. The length of this array becomes 3. In
the third case, we have done away with the new altogether.
a.csclass zzz{public static void Main(){int [] a new int[8] {!--7};}}
o'piler +rrora.cs(8-)/ error %!017/ @ncorrectl& structured arra& initializer
We cannot create a larger array and supply fewer values in the {} brackets. They have to bethe same. Not one more, not one less.
a.csclass zzz{public static void Main(){int[-] b {{!- 0}- {- ,}- {- 8}- {5- 1}- {7- 6}};%&ste'.onsole.rite#ine(b.#ength);foreach ( int i in b)%&ste'.onsole.rite(i $ 9 9);}
}*utput0!! 0 , 8 5 1 7 6
We have created a two dimensional array having a length of five for the innermost rank and
2 for the outermost rank. It is similar to writing 'b = new int[5,2]' and then initializing the
individual members; b[0, 0]=0, b[0, 1]=1 etc. The member Length in System.Array, inherited
by b displays 10 as the total number of members in the array are 5*2. The foreach construct
then displays every member in the array.
a.csclass zzz{public static void Main(){int ,;int[] b new int[];%&ste'.onsole.rite#ine(b.#ength);}}
*utput,
-
8/11/2019 C Sharp the Nuts and Bolts
26/276
243884994.doc 26 od 276
Irrespective of what the documentation has to say, you are allowed to use a variable to
initialize an array. We have used the variable j to create b.
int [][,,][,] a, is a three-dimensional array consisting of two-dimensional arrays which in turn
are of single-dimensional arrays each. The value stored in each element will be an integer.
a.csclass zzz{public static void Main(){int b[];}}o'piler +rrora.cs(8-5)/ error %!58!/ %&nta4 error- bad arra& declarator. =o declare a 'anaged arra& the ranAspecifier precedes the variable3s identifiera.cs(8-1)/ error %088/ @nvalid e4pression ter' 3]3a.cs(8-7)/ error %0!!,/ %&nta4 error- 3]3 e4pected
The array square brackets must come before the name of the variable and not after. These
are issues of syntax and do not follow any coherent pattern. The above line would be a valid
C syntax.
a.csusing %&ste';public class zzz{public static void Main(string[] a){
b&te[][] s new b&te[8][];%&ste'.onsole.rite#ine(s.#ength);for (int i !; i " s.#ength; i$$){s[i] new b&te[i$,];}for (int i !; i " s.#ength; i$$){onsole.rite#ine(9#ength of row {!} is {0}9- i- s[i].#ength);}}}
*utput8#ength of row ! is ,#ength of row 0 is #ength of row is 8#ength of row , is 5#ength of row is 1
A jagged array has a variable number of members. s is a jagged array with 5 members. Each
of these 5 members can be made up of an array of any size. In the first for, we are initializing
s[0], the first member, to an array of bytes which is 3 large. In the second iteration of the for,
s[1] now points to an array of bytes having 4 members. Thus, in the second round,
s[1].Length displays 4.
a.cs
-
8/11/2019 C Sharp the Nuts and Bolts
27/276
243884994.doc 27 od 276
using %&ste';public class zzz{public static void Main(string[] a){int[][] n7 new int[][] { new int[] {-,-}- new int[] {8-5-1-7-6} };int[][] n6 new int[][] { new int[] {-,-}- new int[] {8-5-1-7} };}}
And one more example for the road to ponder on. This shows the levels of complexities that
you can delve in.
a.csclass zzz{public static void Main(){int [] a {0-,};
zzz b new zzz();b.abc(a);b.abc(new int[]{-8});%&ste'.onsole.rite#ine(a[0]);}public void abc( int [] z){%&ste'.onsole.rite#ine(z[0]);z[0] 0!!;}}
*utput
,80!!
You can give an array as a parameter to a function. This can be done in two ways, either by
stating an array name explicitly or by creating an array at the time of creating the function.
There is no way on earth the function can ever know or care on the method you have
adopted. However, an array is passed by reference and any changes made through z will
reflect the values in the original array.
In the second case, even though the changes get incorporated, there is no way of accessing
the array, as we never gave it a name. Change the function abc by adding the params
keyword. This is as shown below.
public void abc(para's int [] z)
and the above program runs exactly the same as earlier. This proves that a params keyword
is nothing but an array parameter.
a.csclass zzz{public static void Main(){
int [] a {0-,};zzz b new zzz();b.abc(a);
-
8/11/2019 C Sharp the Nuts and Bolts
28/276
243884994.doc 28 od 276
b.abc(a-a);}public void abc(int [] &- para's int [] z){%&ste'.onsole.rite#ine(z.#ength);}}
*utput!
There is, however, a major difference between an array and a params parameter. If the
parameter is an array then no other data type can be provided other than an array. Even a
single int has to be passed as an array. However, a params modifier is more flexible as we
are allowed to give individual data types. These are converted into an array. A params
parameter can also be null as in the first invocation of abc. We can either pass an array or
as many individual ints we desire to the second parameter.
a.csclass zzz{public static void Main(){int [] a {0-,};zzz b new zzz();b.abc(out a);%&ste'.onsole.rite#ine(a[]);}public void abc(out int [] z){z new int[,]{0--5};}}
*utput5
With an array, we can also use the modifiers of ref and out. The difference between them is
that in the out modifier, we have to recreate an array within the function despite having
initialized it earlier. An out modifiers demands new entities to be created inside the function.
If the data type is an array, so be it, you must create it and if we do not initialize it, the value
is automatically initialized to zero. Apart from this distinction, the behaviour followed is like
a normal ref entity. Like any normal object, a variable needs to be initialized before using itbut in case of an out, if the array is not initialized, then it takes the default values of the
data type.
An array can be initialized to a null if need arises as a null may mean no value. This also
means that someone somewhere gave it no value.
a.csclass zzz{public static void Main(){
int [] a new int[,]{0-};}}
-
8/11/2019 C Sharp the Nuts and Bolts
29/276
243884994.doc 29 od 276
o'piler +rrora.cs(8-)/ error %!017/ @ncorrectl& structured arra& initializer
Whenever we initialize an array, the size of the array stated in the new and the values to be
initialized must be the same in number. In the above case, we are creating an array of three
ints and supplying values to initialize only two of them. We thought, wrongly so, that the
last member a[2] would be initialized to zero. The compiler proved us wrong by giving us an
error instead.
a.csclass zzz{public static void Main(){int [] a new int[,];%&ste'.onsole.rite#ine(a[!] $ 9.9 $ a[0]);}
}
*utput!.!
An array type is always initialized to the default value of its type. In the above case the
default value is zero as the type of the array is an int.
a.csclass zzz {public static void Main(){int i !;int [] a new int[,]{i$$-i$$-i$$};%&ste'.onsole.rite#ine(a[!] $ 9.9 $ a[0] $ 9.9 $ a[]);}}*utput!.0.
No astonishing facts for a function! Same rules apply here too. No side effects at all. Each
initialization is done independent of each other and starting from left to right.
a.csclass zzz
{public static void Main(){&&& a0 new &&&(0);&&& b0 new &&&(0!);&&& c0 new &&&(0!!);int [] a new int[,] ;tr&{a new int[,]{a0-b0-c0};}catch ( %&ste'.+4ception e){%&ste'.onsole.rite#ine(a[!] $ 9.9 $ a[0] $ 9.9 $ a[]);}%&ste'.onsole.rite#ine(a[!] $ 9.9 $ a[0] $ 9.9 $ a[]);
-
8/11/2019 C Sharp the Nuts and Bolts
30/276
243884994.doc 3 od 276
}}class &&&{public int i;public &&&(int ){i ;}public static i'plicit operator int ( &&& z){%&ste'.onsole.rite#ine(9op 9 $ z.i);if ( z.i 0!)throw new %&ste'.+4ception();return z.i;}}*utputop 0op 0!
!.!.!!.!.!
We create an array of ints and initialize them to objects that smell like yyy's. There is no
problem in doing so as the operator int converts the yyy object into an int.
For the object b1 whose instance variable i has a value 10, we throw an exception. Due to
this, the compiler at run time undoes the initialization of array member a[0] to 1 and it falls
back to the earlier default value of zero. This is the first task it performs on exceptions. The
array members have to be initialized as the initialization statement is in a try block. If we fail
to do so, we get an 'uninitialized variable error'. In this way, we fool the compiler into doing
our bidding.
The array members are, by default, initialized to zero before they get their new values. The
array access element must not be less than zero or greater than the size of the array, or else
an exception is thrown. An initialization statement of int [] a = new int[10][] creates an array
of ten members and each of them in turn is considered to be an array. Each of the 10 arrays
being reference types is initialized to a value null. We cannot, however, do the following.
a.csclass zzz{public static void Main()
{int [][] a new int[,][];}}
o'piler +rrora.cs(8-8)/ error %!017/ @ncorrectl& structured arra& initializera.cs(8-5)/ error %0!!/ ; e4pecteda.cs(8-5)/ error %088/ @nvalid e4pression ter' 3]3
Ha Ha Ha!!! We are overjoyed as we confused the compiler to no end. One error on our part
and the compiler bought the entire cavalry out by giving us three errors instead. We are
forbidden to initialize a sub array at the time of creation, hence the error. They are to be
initialized later and individually, as follows.
a.cs
-
8/11/2019 C Sharp the Nuts and Bolts
31/276
243884994.doc 31 od 276
class zzz{public static void Main(){int [][] a new int[,][];a[!] new int[0];a[0] new int[0!];%&ste'.onsole.rite#ine(a.#ength $ 9 9 $ a[!].#ength $ 9 9 $ a[0].#ength );}}
*utput, 0 0!
The size of the array a is 3 and it contains three members which are an array of ints. The
first one, a[0] contains only one int and the second a[1] has 10 ints. Not permitting the
initialization of sub arrays at the time of creation brings in flexibility as we can now initialize
each of them to any size we wish rather having the same size. In life also, one size does not
fit all ever.
A rectangular array is an array of arrays where all the sub arrays have the same length.
This is more efficient than a multi dimensional array. If we write new int[10][] and initialize
the sub arrays to new int[5], we are creating one main array and 10 sub arrays. However, if
we write int [,] a = new int[10,5] we are only creating one array in all and also it uses only
one statement. Compare and contrast it with the above and choose the one you are most
comfortable with. It is finally a personal decision.
Parameter arraysWhen we use a params parameter in its normal form, the data type to be specified must be
of a type that can be directly or implicitly converted to the parameter array type. A similar
thing happens with a value parameter. In the expanded form, we do not use an array but
pass the parameters individually, which then is converted into an actual array. It is the
compiler's job to create an array of the same data type and width and then initialize the
members with the values stated as parameters. Finally, it uses this array as the params
parameter to the function.
Thus, if we had a simple function abc (params object [] a) and we called the function abc as
abc(1,2,"hell"), then an array would be created as new object[] { 1,2,"hell"}. If the function iscalled with no parameters, then the array becomes an empty array. An array is created after
all.
a.csclass zzz{public static void Main(){int [] a new int[!];}}
There is nothing to feel sorry about when we create an empty array.
-
8/11/2019 C Sharp the Nuts and Bolts
32/276
243884994.doc 32 od 276
a.csclass zzz{public static void Main(){zzz a new zzz();int i 0!;a.abc(i);%&ste'.onsole.rite#ine(i);}public void abc(obect a){%&ste'.onsole.rite#ine(a);a 0!!;}}
*utput0!0!
When calling the function abc, if we do not specify ref or out, then there is no way in hell
that the value of i can be changed within the function. In the above case, we have upgraded
our value parameter, i, to an object using a method called boxing. In spite of it being a
reference type, a, which is an instance of class object, will not reflect any changes made
within the function abc in Main. If you do not believe us, cast i to an object explicitly and yet
nothing changes.
The ther dds and Ends
a.cs
class zzz{public static void Main(){int [] a new int[0!];a[0-] 0!;}}
o'piler +rrora.cs(5-0)/ error %!!/ rong nu'ber of indices inside []- e4pected 303
A one- or a single-dimensional array can only have one indice and not 2. The error tells us
that the compiler checks whether we have given the right number of indices but it does not
check whether we have exceeded the bounds of the array. All this is part and parcel of the
array error handling enforced by the compiler. It is unfortunately very selective in the type of
error handling and some common errors go undetected.a.csstruct zzz{public static void Main(){%&ste'.onsole.rite#ine(9hi9);}}
*utputhi
-
8/11/2019 C Sharp the Nuts and Bolts
33/276
243884994.doc 33 od 276
There is no rule in the world that mandates the Main function to be placed only in a class.
Here we placed it in a structure. Main is the last function in the world to complain.
You cannot place functions anywhere else in your program. All the rules binding other
functions apply to Main also.
a.csclass zzz{public static void Main(){%&ste'.onsole.rite#ine(9hi in zzz9);}}class &&& / zzz{public new static void Main()
{%&ste'.onsole.rite#ine(9hi in &&&9);}}
o'piler +rrora.cs(,-!)/ error %!!01/ 2rogra' 3a.e4e3 has 'ore than one entr& point defined/ 3zzz.Main()3a.cs(0!-)/ error %!!01/ 2rogra' 3a.e4e3 has 'ore than one entr& point defined/ 3&&&.Main()3
In the above program, we have two functions called Main. This results in an error. Hey, but
wait a minute, they are in separate classes, so shouldn't it be acceptable? The compiler
however does not think so. It does not like this specific function, Main being repeated twice
in separate classes. We cannot use the modifiers virtual, new or override, as the function is
static. Always follow the simple dictum, only one love, so only one function called Main!
a.csclass zzz{public static void Main(){&&& a new &&&();a.aa 0!;a.abc(ref a.aa);}
}class &&&{public int aa{get {return !;}set {}}public void abc( ref int b){}}
o'piler +rrora.cs(1-00)/ error %!!5/ : propert& or inde4er 'a& not be passed as an out or ref para'eter
-
8/11/2019 C Sharp the Nuts and Bolts
34/276
243884994.doc 34 od 276
If it walks like a duck, quacks like a duck, it's a duck. A property looks and feels like a
variable but it is actually a series of functions or to be technically correct, accessors. Only a
storage or memory location can be passed as a ref or an out parameter. A property is not
allocated any memory and thus cannot be used wherever a variable can be used. All the
restrictions of static apply to static properties too. The get accessor must terminate either in
a return or a throw statement. Control cannot flow off the accessor body at the end. A setaccessor is like a function that returns void and it has an implicit parameter value.
a.csclass zzz{public static void Main(){&&& a new &&&();a.aa 0!;%&ste'.onsole.rite#ine(a.aa);}}
class &&&{public int -A !;public int aa{get{%&ste'.onsole.rite#ine(9get 9 $ );if ( A !){aa aa $ 0; BB aa$$A 0;}return ;
}set{ value;%&ste'.onsole.rite#ine(9set 9 $ );}}}
The above program does not give any compiler error. We are allowed to change the property
value, within a property. If you do so, the program goes into an indefinite loop. This is
regardless of the fact that by using the value of variable we ensure that the statement aa++
is executed only once.a.csclass zzz{public static void Main(){&&& a new &&&();a.aa 0!;%&ste'.onsole.rite#ine(a.aa);}}class &&&{public int -A !;public int aa{
-
8/11/2019 C Sharp the Nuts and Bolts
35/276
243884994.doc 3 od 276
get{%&ste'.onsole.rite#ine(9get0 9 $ );aa ;%&ste'.onsole.rite#ine(9get 9 $ );return ;}set{ value;%&ste'.onsole.rite#ine(9set 9 $ );}}}
*utputset 0!get0 0!set get
We all have been dumb many a times in life. One proof lies in the above program. Here in
the get accessor of property aa, we are calling the set accessor by giving the statement aa =
4. No indefinite loop but crazy answers!! The long and short story for that matter is, do not
call the get or set accessor with a property directly.
An indexer is similar to a property other than the fact that the indexers, accessors take or
accept parameters. A property is identified by a name, an indexer by its signature.
a.csclass zzz{public static void Main(){ }}class &&&{public static int this[int i]{get {return !;}set {}}}
o'piler +rror
a.cs(7-06)/ error %!0!5/ =he 'odifier 3static3 is not valid for this ite'
Unlike a property, an indexer cannot be static. A property cannot be accessed like an array
or by element access, similar to an indexer. A get and a set accessor share the same
parameter list that the indexer has. A property has no such luck and no parameters at all
but the set receives the implicit parameter value.
In an interface, the only job of an indexer is to declare the signature. Interfaces are smart.
They cannot carry code. All that they do is boss around. They decide the signatures of
functions, indexers etc. so that other people who implement them, follow the rules built in
them.
a.cs
-
8/11/2019 C Sharp the Nuts and Bolts
36/276
243884994.doc 36 od 276
na'espace aaa{int i;}o'piler +rrora.cs(,-0)/ error %!005/ : na'espace does not directl& contain 'e'bers such as fields or'ethods
The compiler is very particular about what you place where. We are not allowed to place
methods and fields directly in a namespace or outside a namespace. Nothing stops us from
placing them in a class. These are the regulations to be followed in the compiler world.
a.csna'espace aaa{public class zzz{public static void Main()
{aaa a;}}}
o'piler +rrorsa.cs(1-0)/ error %!007/ 3aaa3 denotes a 3na'espace3 where a 3class3 was e4pected
Wouldn't you be surprised if you see a tiger instead of a dog? Similarly, we surprised the
compiler. It expected a class/type name and instead comes by the name of a namespace.
The above error is a generic error. If we give the name of a property instead of a class, the
error number will be the same, but the message would change. A single error to take care ofmultiple possibilities. The generic rule clearly states that a CS0118 error number is emitted
whenever the compiler gets something that it does not expect.
a.csna'espace aaa{na'espace bbb.ccc{}}o'piler +rrora.cs(,-00)/ error %!0,/ annot use
-
8/11/2019 C Sharp the Nuts and Bolts
37/276
243884994.doc 37 od 276
We all wanted to come in class but using always beat us to the draw. We have no choice but
to start our code with the using clause. This is a rule imposed upon us by the top brass and
obey, we must.
a.csnew class zzz { }
o'piler +rrorsa.cs(0-0)/ error %08,!/ Ke&word new not allowed on na'espace ele'ents
You cannot use new on namespace elements like class or struct. This is because we create
them in a global namespace.
a.csusing aa %&ste';using aa %&ste';
o'piler +rror
a.cs(-1)/ error %08,1/ =he using alias 3aa3 appeared previousl& in this na'espace
The compiler hates seeing two of anything even though they are the same and cause no
trouble. Thus, two using's are out whether they are the same or different. We are not
allowed to even change our mind.
a.csclass zzz{public static void Main(){string s Lh
i;%&ste'.onsole.rite#ine(s);}}
*utputhi
The @ sign lets you start a string with ". The single change is that you can press enter and
move to the next line, ending the string there. The compiler doesnt show any errors.
a.cs
class zzz{int i {0};}
o'piler +rrora.cs(,-6)/ error %!5/ an onl& use arra& initializer e4pressions to assign to arra& t&pes. =r&using a new e4pression instead.
The array notation can only be used with the array data type. The {} brackets are to be used
exclusively with arrays only.
a.csclass zzz{
-
8/11/2019 C Sharp the Nuts and Bolts
38/276
243884994.doc 38 od 276
public int[] a { - ,- {}};}o'piler +rrora.cs(,-5)/ error %!5,/ :rra& initializers can onl& be used in a variable or field initializer. =r&using a new e4pression instead.
We cannot use the {} brackets to initialize an array within an array. For that we have to usethe keyword new instead. The {} can only be used for a single dimensional array.
a.cspublic class zzz{int a[];}
o'piler +rrora.cs(,-5)/ error %!58!/ %&nta4 error- bad arra& declarator. =o declare a 'anaged arra& the ranAspecifier precedes the variable3s identifier
There is lots that the C# language has copied from C and C++ and along the way, it has
changed the syntax of a few in the language. The array brackets must come before the name
of the variable and we are not allowed to state the size of the array within them either. All
this worked very well in C/C++, C# in this case looks a lot like Java.
a.csclass zzz{public static void Main(string a [] ){}}
o'piler +rrora.cs(,-,)/ error %088/ :rra& t&pe specifier- []- 'ust appear before para'eter na'e
Array brackets [] can only be in one place. This is before the name of the array, not after.
God alone knows why?!
a.csclass zzz{public static void Main(){
int[] a {0--,};foreach (int in a){}}}
o'piler +rrora.cs(5-0)/ error %!,!/ =&pe and identifier are both re
-
8/11/2019 C Sharp the Nuts and Bolts
39/276
243884994.doc 39 od 276
Statements
C# provides us with a countless number of statements. Let us now understand each one of
them in detail.
a.cspublic class zzz{public static void Main(){bool i false;if ( i)int !;}}
o'piler +rrorsa.cs(1-0)/ error %0!,/ +'bedded state'ent cannot be a declaration or labeled state'ent
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.cspublic class zzz{public static void Main(){int i ,!;const int ,!;if ( i ,)
%&ste'.onsole.rite#ine(9hi9);if ( ,)%&ste'.onsole.rite#ine(9hi9);}}
o'piler arninga.cs(0!-0)/ warning %!05/ Hnreachable 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.
-
8/11/2019 C Sharp the Nuts and Bolts
40/276
243884994.doc 4 od 276
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 flowanalysis. 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 (4) if (&) I(); else N();if (4) {
if (&) {I();
}else {
N();
}}
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.cspublic class zzz{public static void Main(){zzz a new zzz();a.abc(0);a.abc(0!);}void abc(int i){switch (i){case !/%&ste'.onsole.rite#ine(9zero9);breaA;
case 0/%&ste'.onsole.rite#ine(9one9);breaA;default/%&ste'.onsole.rite#ine(9end9);breaA;}}}*utputoneend
-
8/11/2019 C Sharp the Nuts and Bolts
41/276
243884994.doc 41 od 276
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 thecase 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.cspublic class zzz{public static void Main(){}void abc(int i){switch (i){case !/%&ste'.onsole.rite#ine(9zero9);case 0/%&ste'.onsole.rite#ine(9one9);breaA;}}}o'piler +rror
a.cs(7-0)/ error %!05,/ ontrol cannot fall through fro' one case label (3case !/3) 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.cspublic class zzz{
public static void Main(){zzz z new zzz();z.abc(!);}void abc(int i){switch (i){case !/%&ste'.onsole.rite#ine(9second9);goto case 0;case 0/
%&ste'.onsole.rite#ine(9first9);breaA;}
-
8/11/2019 C Sharp the Nuts and Bolts
42/276
243884994.doc 42 od 276
}}
*utput
secondfirst
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.cspublic class zzz{public static void Main()
{zzz z new zzz();z.abc(!);}void abc(int i){switch (i){case !/%&ste'.onsole.rite#ine(9second9);goto case 0;%&ste'.onsole.rite#ine(9hi9);case 0/%&ste'.onsole.rite#ine(9first9);
breaA;}}}
o'piler arninga.cs(08-0)/ warning %!05/ Hnreachable code detected*utputsecondfirst
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.cspublic class zzz{
public static void Main(){zzz z new zzz();
-
8/11/2019 C Sharp the Nuts and Bolts
43/276
243884994.doc 43 od 276
z.abc(!);z.abc(,);z.abc(0);}void abc(int i){switch (i){case !/%&ste'.onsole.rite#ine(9zero9);goto case ,;case 0/%&ste'.onsole.rite#ine(9one9);goto default;case ,/%&ste'.onsole.rite#ine(9two9);breaA;default/%&ste'.onsole.rite#ine(9last9);breaA;
}}}
*utputzerotwotwoonelast
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.cspublic class zzz{public static void Main(){}void abc(int i){switch (i){case !/while ( true) ;case 0/return ;case ,/throw new %&ste'.+4ception();}}}
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 atall as i being zero will enter the while and never leave the case.
-
8/11/2019 C Sharp the Nuts and Bolts
44/276
243884994.doc 44 od 276
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.cspublic class zzz{public static void Main(){}void abc(int i){switch (i){case !/%&ste'.onsole.rite#ine(9zero9);breaA;
case !/%&ste'.onsole.rite#ine(9one9);breaA;}}}
o'piler +rrora.cs(0,-5)/ error %!08/ =he label 3case !/3 alread& occurs in this switch state'ent
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 atthe 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.cspublic class zzz{
int 0!;public static void Main(){}void abc(int i){switch (i){case /breaA;case > /%&ste'.onsole.rite#ine(9zero9);breaA;
}}}
-
8/11/2019 C Sharp the Nuts and Bolts
45/276
243884994.doc 4 od 276
o'piler +rrora.cs(00-5)/ error %!08!/ : constant value is e4pecteda.cs(0,-5)/ error %!!6/ annot i'plicitl& convert t&pe 3bool3 to 3int3
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 constantvalue. 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.cspublic class zzz{public static void Main(){zzz z new zzz();z.abc(1);
z.abc(1!);}void abc(int i){switch (i > 7){case > 8/%&ste'.onsole.rite#ine(9first9);breaA;case " 8/%&ste'.onsole.rite#ine(9second9);breaA;}}
}
*utputfirstsecond
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 ! > 8/%&ste'.onsole.rite#ine(9third9);breaA;
and we got the following error
o'piler +rrora.cs(06-5)/ error %!08/ =he label 3case 0/3 alread& occurs in this switch state'ent
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 notadmissible. The error delivers the same message. In the above case, the compiler should
-
8/11/2019 C Sharp the Nuts and Bolts
46/276
243884994.doc 46 od 276
take up the Hitlerian attitude and erase all our code; to punish us for writing such
gibberish.
a.cspublic class zzz{
public static void Main(){zzz z new zzz();&&& a new &&&();z.abc(a);}void abc(&&& i){switch (i){case !/%&ste'.onsole.rite#ine(9second9);breaA;
case 0/%&ste'.onsole.rite#ine(9first9);breaA;}}}class &&&{}
o'piler +rrora.cs(00-6)/ error %!080/ : value of an integral t&pe e4pected
The C# compiler informs us that a switch statement can only take certain integral types. Tobe 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.cspublic class zzz{public static void Main(){zzz z new zzz();&&& a new &&&();z.abc(a);
}void abc(&&& i){switch (i){case !/%&ste'.onsole.rite#ine(9second9);breaA;case 0/%&ste'.onsole.rite#ine(9first9);breaA;}}
}class &&&{
-
8/11/2019 C Sharp the Nuts and Bolts
47/276
243884994.doc 47 od 276
public static i'plicit operator int ( &&& a){%&ste'.onsole.rite#ine(9operator9);return 0;} }
*utputoperatorfirst
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.cspublic class zzz
{public static void Main(){zzz z new zzz();&&& a new &&&();z.abc(a);}void abc(&&& i){switch (i){case !/%&ste'.onsole.rite#ine(9second9);breaA;
case 0/%&ste'.onsole.rite#ine(9first9);breaA;}}}class &&&{public static i'plicit operator int ( &&& a){%&ste'.onsole.rite#ine(9operator9);return 0;}
public static i'plicit operator b&te ( &&& a){%&ste'.onsole.rite#ine(9operator9);return 0;}}
o'piler +rrora.cs(00-6)/ error %!080/ : value of an integral t&pe e4pected
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.
-
8/11/2019 C Sharp the Nuts and Bolts
48/276
243884994.doc 48 od 276
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.cspublic class zzz{public static void Main(){zzz z new zzz();z.abc();z.abc(,);}void abc(int i){switch (i){case !/%&ste'.onsole.rite#ine(9first9);
breaA;case ,/case /%&ste'.onsole.rite#ine(9second9);breaA;}}}
*utputsecondsecond
You can have many case statements bunched up together. There will be no errors if you doso. 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.cspublic class zzz{public static void Main(){zzz a new zzz();a.abc(!);}void abc(int i){switch (i)
{case !/int 1;
-
8/11/2019 C Sharp the Nuts and Bolts
49/276
243884994.doc 49 od 276
%&ste'.onsole.rite#ine();breaA;}}}
*utput1
a.cspublic class zzz{public static void Main(){zzz a new zzz();a.abc(!);}void abc(int i){switch (i){int 1;case !/int A 1;breaA;case 0/%&ste'.onsole.rite#ine(A);breaA;}}}o'piler +rror
a.cs(0-0)/ error %08,/ =he Ae&word case or default 'ust precede code in switch blocA
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.
o'piler +rrora.cs(05-5)/ error %!058/ Hse of unassigned local variable 3A3
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.cspublic class zzz{public static void Main(){}void abc(int i){goto aa;
-
8/11/2019 C Sharp the Nuts and Bolts
50/276
243884994.doc od 276
aa/}}
o'piler +rrora.cs(0!-0)/ error %088/ @nvalid e4pression ter' 3}3
a.cs(00-0)/ error %0!!/ ; e4pected
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.cspublic 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. ;)
!oopsIn all, we have four iterative statements, the for, foreach, while and the last kid on the block,
the do while.
a.cspublic class zzz {public static void Main() {int i 0;do{%&ste'.onsole.rite(i $ 9 9);i$$;
} while ( i " ,);}}*utput0 ,
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
-
8/11/2019 C Sharp the Nuts and Bolts
51/276
243884994.doc 1 od 276
public class zzz {public static void Main() {int i 0;do{%&ste'.onsole.rite(i $ 9 9);i$$;} while ( i " !);i 0;while ( i " ! ) {%&ste'.onsole.rite(i $ 9...9);i$$;}}}*utput0
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
-
8/11/2019 C Sharp the Nuts and Bolts
52/276
243884994.doc 2 od 276
a.cspublic class zzz{public static void Main(){int [] a new int[,]{0--,};foreach ( int i in a){%&ste'.onsole.rite(i $ 9 9);i 0!;zzz.abc(ref i);%&ste'.onsole.rite#ine(i);}}public static void abc(ref int ){%&ste'.onsole.rite(9abc 9 $ $ 9 9); 0!!;}}
o'piler +rrora.cs(6-0)/ error %05!/ annot assign to 3i3 because it is readOonl&a.cs(0!-0,)/ error %05!8/ annot pass 3i3 as a ref or out argu'ent because it is readOonl&
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.
"ump 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 fiveconditional 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.cspublic class zzz{public static void Main()
{breaA;}}
o'piler +rrora.cs(8-0)/ error %!0,6/ Fo enclosing loop out of which to breaA or continue
You cannot have a break statement by itself. It has to be placed within a case or a loop
construct.
a.cspublic class zzz {public static void Main() {int i 0- 0;
-
8/11/2019 C Sharp the Nuts and Bolts
53/276
243884994.doc 3 od 276
for ( i 0; i" 0! ; i$$) {if ( i ,)breaA;for ( 0; " 0!; $$){%&ste'.onsole.rite#ine(i $ 9.9 $ );if ( 0)breaA;}}%&ste'.onsole.rite#ine(i $ 9 9 $ );}}*utput0.0.0, 0
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.cspublic class zzz{public static void Main()
{int i 0- 0;for ( i 0; i" 0! ; i$$){if ( i ,)breaA;for ( 0; " 0!; $$){%&ste'.onsole.rite#ine(i $ 9.9 $ );if ( 0)goto aa ;}}aa/
%&ste'.onsole.rite#ine(i $ 9 9 $ );}}
*utput0.00 0
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 havebeen reading all about goto.
-
8/11/2019 C Sharp the Nuts and Bolts
54/276
243884994.doc 4 od 276
a.cspublic class zzz {public static void Main() {int i 0;for ( i 0; i" 0! ; i$$)
{tr&{%&ste'.onsole.rite#ine(90 tr&9);
tr&{%&ste'.onsole.rite#ine(9 tr&9);breaA;}finall&{%&ste'.onsole.rite#ine(9 finall&9);}
}
finall&{%&ste'.onsole.rite#ine(90 finall&9);}}%&ste'.onsole.rite#ine(i);}}
*utput0 tr& tr& finall&
0 finall&0
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 andthe above explanation will still hold true.
a.cspublic class zzz{public static void Main(){int i 0;for ( i 0; i" 0! ; i$$){goto aa;}
{aa/%&ste'.onsole.rite#ine(i);
-
8/11/2019 C Sharp the Nuts and Bolts
55/276
243884994.doc od 276
}}}
o'piler +rrora.cs(7-0)/ error %!086/ Fo such label 3aa3 within the scope of the goto state'ent
o'piler arninga.cs(00-0)/ warning %!05/ =his 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.cspublic class zzz{public static void Main(){goto aa;{aa/;}}}
o'piler +rrora.cs(8-0)/ error %!086/ Fo such label 3aa3 within the scope of the goto state'ento'piler arninga.cs(1-0)/ warning %!05/ Hnreachable code detecteda.cs(1-0)/ warning %!05/ =his 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.cspublic class zzz{public static void Main(){for ( int i 0; i" 0! ; i$$)
{tr&{}finall&{breaA;return ;}}}}
o'piler +rrora.cs(0-0)/ error %!081/ ontrol cannot leave the bod& of a finall& clause
-
8/11/2019 C Sharp the Nuts and Bolts
56/276
243884994.doc 6 od 276
o'piler arninga.cs(0,-0)/ warning %!05/ Hnreachable code detectedo'piler +rrora.cs(0,-0)/ error %!081/ ontrol cannot leave the bod& of a finall& 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.cspublic class zzz{public static void Main()
{for ( int i 0; i" ,; i$$){%&ste'.onsole.rite#ine(99 $ i);continue;%&ste'.onsole.rite#ine(9:9 $ i);}}}*utput0,
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 pointof 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.cspublic class zzz{public static void Main(){int aa 0!;goto aa ;
-
8/11/2019 C Sharp the Nuts and Bolts
57/276
243884994.doc 7 od 276
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 differentnamespaces, 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 ther dds and Ends
a.csclass zzz{public static void Main(){aa/ ;aa/ ;}}o'piler +rrorsa.cs(1-0)/ error %!0!/ =he label 3aa3 is a duplicate
Nothing, read my lips, Nothing can ever be a duplicate. Not even a label.
a.csclass zzz {public static void Main(){goto case 8 ;}}
o'piler +rrorsa.cs(8-0)/ error %!08,/ : goto case is onl& valid inside a switch state'ent
A goto case statement only fits in a case statement. It cannot be used outside a case.
a.csclass &&&{}class zzz{
public static void Main(){la/
-
8/11/2019 C Sharp the Nuts and Bolts
58/276
243884994.doc 8 od 276
;{la/;goto la;}}}
o'piler +rrora.cs(0,-0)/ error %!087/ =he label 3la3 shadows another label b& the sa'e na'e in a containedscope
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.csclass zzz {public static void Main(){if ( true) ;}}o'piler arninga.cs(8-0)/ warning %!5/ 2ossible 'istaAen null state'ent
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.csclass zzz{public static void Main(){int i 5;switch(i){}}}
o'piler arninga.cs(7-0)/ warning %08/ +'pt& switch blocA
m!ty vesses make the most noise. he com!ier does not understand anythin" em!ty
incudin" a s#itch statement. ea$+ it is ony a #arnin" and can 'e i"nored
Chapter 3
Enums
An enum is at the same level as a class, struct and interface. It performs a similar job of
creating a new data type.
-
8/11/2019 C Sharp the Nuts and Bolts
59/276