Thursday, February 15, 2007

c# KeyWord Tokens....













Introduction



I expected that
learning C# would be easy considering my extensive C++ background.
Interestingly, I haven’t found this to be particularly true. There are subtle
differences between the languages which will trip up the C++ programmer, and
there’s quite a few new things in C# (and features that C++ has but are missing
from C#) to make life just a little more complicated than I expected. I
realized that while I am “functional” in C#, I am far from being “proficient”.



I figured it
was time to get back to basics and really explore the language in the way
languages used to be taught in the old days: start with the keywords, then move
into the syntax, and then start writing some basic (as in simple!) programs.



So, for all
those interested, this article gives a synopsis of the various keywords in C#.
The reader should be familiar with C++ or at least the concepts of classes and
objects. In some ways, this is a beginner’s tutorial, but in other ways, it can
be a very useful quick reference guide to the C++ veteran (especially the use
of the override and new modifiers).



A really good
place to begin is this site
<http://msdn.microsoft.com/library/default.asp?url=/library/en-us/csref/html/vcoricprogrammersreference.asp>

provided by Microsoft.



The Keywords



Following is a
table of the keywords in C#. Unfortunately, they are organized alphabetically,
instead of categorically.





























































































































abstract



event



new



struct



as



explicit



null



switch



base



extern



object



this



bool



false



operator



throw



break



finally



out



true



byte



fixed



override



try



case



float



params



typeof



catch



for



private



uint



char



foreach



protected



ulong



checked



goto



public



unchecked



class



if



readonly



unsafe



const



implicit



ref



ushort



continue



in



return



using



decimal



int



sbyte



virtual



default



interface



sealed



volatile



delegate



internal



short



void



do



is



sizeof



while



double



lock



stackalloc





else



long



static





enum



namespace



string






Note that
“value” is left out of this list, but it is syntax highlighted like a keyword
in the IDE.



Let’s take this
list and create some categories so that we can better organize and understand
the keywords. Now, a disclaimer: I am not a compiler expert, nor have I cracked
open a book on programming in a long time, so you’ll have to forgive me if you
don’t like the categorization of some of your favorite keywords!



Keywords that modify a class, method,
property, or field:



·
abstract



·
const



·
extern



·
internal



·
new



·
override



·
private



·
protected



·
public



·
readonly



·
sealed



·
static



·
virtual



·
volatile



·
void



Keywords dealing with object type and
type conversions:



·
as



·
explicit



·
implicit



·
is



·
operator



·
sizeof



·
typeof



Keywords that are aliases to built in
types, are specific types, or have to do with enumerations:



·
bool



·
byte



·
char



·
class



·
decimal



·
double



·
enum



·
float



·
int



·
interface



·
long



·
object



·
sbyte



·
short



·
string



·
struct



·
uint



·
ulong



·
ushort



Keywords that control program flow:



·
break



·
case



·
continue



·
default



·
do



·
else



·
for



·
foreach, in



·
goto



·
if



·
return



·
switch



·
while



Keywords that are used in exception
handling:



·
catch



·
checked



·
finally



·
throw



·
try



·
unchecked



Keywords that are like C++ function
pointers and related subjects:



·
delegate



·
event



Keywords that affect garbage
collection:



·
fixed



Keywords to help with critical sections
of code:



·
lock



Keywords that declare scope:



·
namespace



Keywords that control object
allocation/destruction:



·
new



·
stackalloc



Keywords that affect method parameter
passing:



·
out



·
params



·
ref



Keywords that are literals or refer to
the current instance of an object:



·
null



·
false



·
true



·
this



·
value



Keywords dealing with unmanaged code:



·
unsafe



Keywords, miscellaneous:



·
base



·
void



Keywords That Modify Accessibility



In Part I, I'll
look specifically at the keywords that modify the accessibility of classes,
methods, fields and properties. MSDN provides excellent descriptions of these
keywords, so I have two choices here—I can either plagiarize what they’ve
already done, or I could write my own descriptions based on my own
understanding, which may or may not be as complete, accurate or useful. I opted
for the second option, as this way, I’ll end up writing little code snippets to
try things out, and I’ll have learned something along the way (whether you will
learn something, well, I don’t know about that).



abstract



Abstract
class



When used as a
modifier for a class, this keyword declares the class as being intended to be
used only as a base class for other classes. You cannot directly instantiate an
abstract class. For this reason, the sealed modifier can’t be used, because
this prevents an abstract class from being inherited. An abstract class can
have members that implement actual functionality, as compared to an interface.



Abstract
classes are useful when providing generic functionality to a class structure.
As the name implies, an abstract class should represent the abstraction of some
object.



Abstract
method



When used as a
modifier for a method, the method does not have an implementation—the
implementation must be provided by the derived class. Because abstract methods
are implicitly virtual (meaning a derived class must provide the
implementation), the derived class must use the keyword override as part of the
declaration of the inherited class’ abstract method.



Abstract
methods are useful as a placeholder for a common process shared by specific
implementations. Unlike virtual methods, in which the base class can provide
some generic implementation, an abstract method forces the programmer to
provide an implementation in all derived classes. This may be done because
there is no generic implementation that is reasonable to provide.



Abstract
attribute



An attribute
can be abstract as well, which also requires that its implementation be
provided by the derived class. Furthermore, abstract attributes cannot be
static because they must be implemented in the derived class.



Abstract
attributes are useful in the same situations as described for abstract methods.



Example:























Collapse



abstract class AbstractClass



{



public int
i=5;



public
void Method()



{




Console.WriteLine("AbstractClass::Method() i="+i.ToString());



}





// can't
have an implementation:



public
abstract void AbstractMethod();





// the
property cannot have an implementation either:



public
abstract int I



{



get;



}



}





class ConcreteClass : AbstractClass



{



// because
there's an abstract method in the inherited class,



// we have
to provide the implementation here. Note
that we must



// also
provide the "override" keyword.



public
override void AbstractMethod()



{




Console.WriteLine("ConcreteClass:AbstractMethod");



}





//
similarly, for the property:



public
override int I



{



get
{return i;}



}



}





// can't do: AbstractClass abstractClass=new
AbstractClass();



ConcreteClass concreteClass=new ConcreteClass();



concreteClass.Method();



concreteClass.AbstractMethod();



Console.WriteLine("I="+concreteClass.I.ToString());



const and readonly



The const
keyword only applies to variables, which MSDN calls “fields”. A field with the
const keyword indicates that the field cannot be changed. The value of the
field must be initialized in the declaration. Interestingly, attributes cannot
be declared as const, and furthermore, attributes referring to const fields can
only have getters, not setters.



In C++, the const keyword was
also used to indicate that the method did not modify any variables:



void Foo() const;



or that the
method returned a reference that could not be modified:



const int& Foo();



or that the
parameter being passed as a reference could not be modified by the method:



void Foo(const int& i);



which could
lead to some ridiculous but valid statements:



const int& Foo(const int& i) const;



Happily, C#
treats the keyword const with only one meaning.



Declaring
fields as const protects both you and other programmers from accidentally
changing the value of the field. Also note that with const fields, the compiler
performs some optimization by not declaring any stack space for the field. For
example:



const int foo=10;



int bar=16;



results in
stack space being used for bar:



00000020 mov
dword ptr [ebp-8],10h



but not for foo, which is loaded
into a register as an immediate value:



Console.WriteLine("foo="+foo.ToString()+",
bar="+bar.ToString());



00000096
mov dword ptr
[ebp-18h],0Ah ; foo



0000009d
mov edi,dword ptr
ds:[01C40070h]



000000a3
lea ecx,[ebp-18h]



000000a6
call dword ptr
ds:[02EA2758h]



000000ac
mov dword ptr
[ebp-1Ch],eax



000000af
mov eax,dword ptr
ds:[01C40074h]



000000b5
mov dword ptr
[ebp-20h],eax



000000b8
lea ecx,[ebp-8] ; bar



Furthermore,
const can only be applied to intrinsic types. You can’t say:



const HasConstField hcf2=new HasConstField();



Example:



class HasConstField



{



public
HasConstField(); // can't do: {i=3;}



public
const int i=1;





public int
I



{



get
{return i;}



//
can't do: set {i=5;}



}



}



HasConstField hcf=new HasConstField();



// can't do: hcf.i=3;



The readonly
keyword is similar to const, with two exceptions. First, the storage of a
readonly field is the same as a regular (read-write) field, and thus there is
no performance benefit. Secondly, readonly fields can be initialized in the
constructor of the containing class.



For example
(from MSDN):



public class ReadOnlyTest



{



class
MyClass



{



public
int x;



public
readonly int y = 25; // Initialize a readonly field



public
readonly int z;





public
MyClass()



{



z =
24; // Initialize a readonly instance
field



}





public
MyClass(int p1, int p2, int p3)



{



x =
p1;



y =
p2;



z =
p3;



}



}



}



extern



The extern
keyword is basically used just for non-C# function calls, which also requires:



using System.Runtime.InteropServices;



and is used in
conjunction with the DllImport attribute, so that your C# program can call
functions in other DLLs. This is a very useful capability of the C# language,
because there are cases where you need direct access to the underlying Windows
API.



Example:



[DllImport("User32.dll")]



public static extern int MessageBox(int h, string m,
string c, int type);





MessageBox(0, "Test", "My Message
Box", 0);



internal



The internal
keyword restricts the visibility of the member to just the specific files in
the assembly in which the internal class is declared.



For classes, an
internal class and its members (public or not) are not visible to any programs
that reference the assembly.



For methods,
fields and properties, using the internal keyword limits the visibility of that
member to just the assembly. Thus, you can have a class visible to the outside
world, but the class can contain methods, fields and properties that are
visible only within the assembly. Compare this to the protected and private
keywords, which restrict access of members to derived classes and the class
methods themselves, respectively.



Also, all
internal members are treated as public within the scope of the assembly. The
only exception to this is the “protected internal” member which limits access
to just derived classes. This allows the programmer to control the access to
the member within the assembly (ensuring non-derived objects don’t tamper with
the value or access the function), while also making the method or field
inaccessible outside of the assembly.



Example:





Collapse



// This class is only visible to this assembly.



internal class InternalClass



{



}





class InternalTestClass



{



// this
field is visible only within this assembly.



internal
int i=2;



// this
method is visible only within this assembly.



internal
void InternalMethod()



{




Console.WriteLine("InternalMethod");



}



// this
protected method can only be invoked by derived classes.



internal
protected void InternalProtectedMethod()



{




Console.WriteLine("InternalProtectedMethod");



}



// this
attribute is visible only within this assembly.



internal
int I



{



get
{return i;}



set
{i=value;}



}



}





InternalTestClass itc=new InternalTestClass();



itc.I+=5;



Console.WriteLine("I="+itc.i.ToString());



itc.InternalMethod();



new, override, and virtual



Well, just when
I thought C# tried to give only one meaning to keywords, I discover this gem.
The keyword new, in addition to being used as an operator, can be used as a
modifier to explicitly hide a member inherited from a base class (MSDN).
Furthermore, MSDN states: Using new and virtual together guarantees a new point
of specialization. Compare this with the MSDN definition for virtual: An
override method provides a new implementation of a member inherited from a base
class. Let’s explore what all this means. Also note that it is impossible to
discuss the new modifier without also discussing the override modifier,
therefore these two have been lumped together.



To
explicitly hide a member inherited from a base class



First off, the
new modifier is used exclusively with members of a derived class. A basic use
of the new modifier is to declare a method in the derived class that just so
happens to have the same name as a method in the base class. Without the new
modifier, one gets the well known error “foo hides inherited member blah”,
which is a common problem in C++. The new modifier allows a method in the
derived class to have the same name as a method in the inherited class
(assuming all else is the same—return type and parameter lists).



Example 1:



class NewBaseClass



{



public
void NonVirtualMethod()



{




Console.WriteLine("NewBaseClass:NonVirtualMethod");



}



}





class NewClassA : NewBaseClass



{



public new
void NonVirtualMethod()



{




Console.WriteLine("NewClassA:NonVirtualMethod");




base.NonVirtualMethod();



}



}



In this
example, the NonVirtualMethod
method of the base class is hidden from the derived class, so it can have its
own implementation but use the same name.



Using new
and virtual together guarantees a new point of specialization



Now, things get
more interesting when the inherited method has been declared as virtual. First,
take a look at the following C# classes:



Example 2A:



class VirtualClass



{



public
virtual void VirtualMethod()



{




Console.WriteLine("VirtualClass:VirtualMethod");



}



}





class OverrideClassA : VirtualClass



{



public
override void VirtualMethod()



{




Console.WriteLine("OverrideClassA:VirtualMethod");




base.VirtualMethod();



}



}





class OverrideClassB : OverrideClassA



{



public
override void VirtualMethod()



{




Console.WriteLine("OverrideClassB:VirtualMethod");




base.VirtualMethod();



}



}



and the test
code:



Example 2B:



OverrideClassB ocb=new OverrideClassB();



ocb.VirtualMethod();



((OverrideClassA)ocb).VirtualMethod();



((VirtualClass)ocb).VirtualMethod();



resulting in:



OverrideClassB:VirtualMethod



OverrideClassA:VirtualMethod



VirtualClass:VirtualMethod



OverrideClassB:VirtualMethod



OverrideClassA:VirtualMethod



VirtualClass:VirtualMethod



OverrideClassB:VirtualMethod



OverrideClassA:VirtualMethod



VirtualClass:VirtualMethod



Now compare the
above class definition with the following:



Example 2C:



class NewBaseClass



{



public
virtual void VirtualMethod()



{




Console.WriteLine("NewBaseClass:VirtualMethod");



}



}





class NewClassA : NewBaseClass



{



public new
void VirtualMethod()



{




Console.WriteLine("NewClassA:VirtualMethod");




base.VirtualMethod();



}



}





class NewClassB : NewClassA



{



public new
void VirtualMethod()



{




Console.WriteLine("NewClassB:VirtualMethod");




base.VirtualMethod();



}



}



And note the
use of the new modifier. When the following code is run:



Example 2D:



NewClassB ncb=new NewClassB();



ncb.VirtualMethod();



((NewClassA)ncb).VirtualMethod();



((NewBaseClass)ncb).VirtualMethod();



we get:



OverrideClassB:VirtualMethod



OverrideClassA:VirtualMethod



VirtualClass:VirtualMethod



OverrideClassA:VirtualMethod



VirtualClass:VirtualMethod



VirtualClass:VirtualMethod



Now, the cast
allows us to access the specific base class member, because the derived class
provides a new specialization, meaning that it doesn’t simply provide an
implementation of the base class method, it provides a specialization. This is a
critical distinction.



When
implementing a class, the programmer must consider whether the class methods
provide specialization vs. always override the base class functionality. One
rule of thumb is to always assume specialization, except in the case of abstract
classes, methods or interfaces, all of which must be overridden by the derived
class.



Note that if
the inherited class’ method has been declared private, it is already hidden
from the derived class and therefore the new modifier is not necessary. Also
note that a virtual member cannot be private, because it is impossible to
override a private member—it is private to the class that implements it.



One final
point—inspecting the resulting assembly code shows that there is no difference
in performance between invoking members that are modified with the new keyword
vs. the override keyword.



private, protected, and public



These three
modifiers affect the accessibility of methods, fields and attributes. The
private modifier ensures that the method, field or attribute is visible only
within the class it is defined. The protected modifier extends this visibility
to derived classes, and the public modifier declares the method, field or
attribute to be visible to everyone.



These three
modifiers are fundamental to a good object oriented design. Much progress can
be made towards reducing potential bugs by restricting visibility and access to
methods, fields and attributes. However, inappropriate use of these modifiers
can result in classes that are not extensible because visibility/access is
incorrectly configured.



For example:



class PPP



{



private
int a=0;



public int
A



{



get
{return a;}



set
{a=value;}



}



protected
int A2



{



get
{return a*2;}



set
{a=value/2;}



}



public int
GetA() {return a;}



protected
int GetA2() {return a*2;}



private
void SetA2(int a2) {a=a2/2;}



}



sealed



The sealed
modifier ensures that a class cannot be inherited. Therefore, sealed classes
cannot be abstract, nor can they have abstract or virtual methods. There have
been several complaints that some classes in the .NET environment shouldn’t
have been sealed by the designers at Microsoft, so be careful when considering
whether to seal your own classes. Similar to using the public, protected and
private modifiers, using the sealed modifier on a class can make your object
model difficult, if not impossible, to extend.



static



A method, field
or property that has been modified with the static keyword is accessible
without requiring an instance of the containing class. A static field is shared
between all instances of an object. Also, methods and fields modified by the
static keyword is a mechanism for providing “global” functions and variables.



For example:



class StaticClass



{



public
static int a=0;





public int
A



{



get
{return a;}



set
{a=value;}



}



}





StaticClass sc1=new StaticClass();



StaticClass sc2=new StaticClass();



sc1.A=10;



Console.WriteLine("sc2.A="+sc2.A.ToString());



StaticClass.a=20;



Console.WriteLine("sc1.A="+sc1.A.ToString());



Console.WriteLine("sc2.A="+sc2.A.ToString());



Outputs:



Sc2.A=10



Sc1.A=20



Sc2.A=20



Illustrating
how even though a
was set using instance sc1,
it affected instance s1,
and similarly how field a
can be set without even needing an instance of the class, and its effects on
instances.



volatile



This keyword
modifies how the compiler generates code that reads and writes the contents of
a field that uses this keyword. Using the volatile modifier ensures that the
compiler generates code that always reads from the field’s memory location (as
opposed to optimizing by perhaps re-using a register that was previously loaded
with the field’s value), and immediately writes a value to the field (as
opposed to postponing the write because it may be more efficient to do it
later).



This keyword is
useful when an external process (like the operating system or a thread in your
application) can potentially modify the value of a field, and you need to
ensure that you are reading the most current value.



Unfortunately,
I cannot seem to get the C# compiler to generate code to demonstrate the
differences between volatile and non-volatile memory reads, even with the
optimization flag turned on. This is probably because of poor optimization in
C#.



void



The void
keyword modifies a method, indicating that it does not have a return value.
Unlike C++, you cannot use the void keyword in the argument list, which was an
allowable (if not acceptable) practice for indicating that a method did not
have any parameters.



Conclusion



By thoroughly
reviewing the keywords in C#, especially the modifier keywords, the transition
from C++ to C# can be much less confusing and much simpler for the programmer.







No comments: