C# Keywords, Part I - Modifier Keywords - CodeProject
C# Keywords, Part I - Modifier Keywords - CodeProject
Introduction
I expected that learning C# would be easy considering my extensive C++ background. Interestingly, I havent found this to be particularly true. There are subtle differences between the languages which will trip up the C++ programmer, and theres 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 beginners tutorial, but in other ways, it can be a very useful quick reference guide to the C++ veteran (especially the use of the o v e r r i d eand n e w modifiers). A really good place to begin is this site provided by Microsoft.
The Keywords
Following is a table of the keywords in C#. Unfortunately, they are organized alphabetically, instead of categorically.
a b s t r a c t e v e n t a s e x p l i c i t b a s e e x t e r n b o o l f a l s e b r e a k f i n a l l y b y t e f i x e d c a s e f l o a t
n e w n u l l o b j e c t o p e r a t o r o u t o v e r r i d e p a r a m s
s t r u c t s w i t c h t h i s t h r o w t r u e t r y t y p e o f
c a t c h f o r p r i v a t e c h a r f o r e a c h p r o t e c t e d c h e c k e dg o t o p u b l i c c l a s s i f r e a d o n l y c o n s t i m p l i c i t r e f c o n t i n u e i n r e t u r n d e c i m a li n t s b y t e d e f a u l ti n t e r f a c es e a l e d d e l e g a t e i n t e r n a l s h o r t d o i s s i z e o f d o u b l e l o c k s t a c k a l l o c e l s e l o n g s t a t i c e n u m n a m e s p a c es t r i n g
u i n t u l o n g u n c h e c k e d u n s a f e u s h o r t u s i n g v i r t u a l v o l a t i l e v o i d w h i l e
Note that v a l u e is left out of this list, but it is syntax highlighted like a keyword in the IDE. Lets 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 youll have to forgive me if you dont like the categorization of some of your favorite keywords!
Keywords that are aliases to built in types, are specific types, or have to do with
enumerations:
b o o l b y t e c h a r c l a s s d e c i m a l d o u b l e e n u m f l o a t i n t i n t e r f a c e l o n g o b j e c t s b y t e s h o r t s t r i n g s t r u c t u i n t u l o n g u s h o r t
Keywords that are like C++ function pointers and related subjects:
d e l e g a t e
e v e n t
Keywords, miscellaneous:
b a s e v o i d
this way, Ill end up writing little code snippets to try things out, and Ill have learned something along the way (whether you will learn something, well, I dont 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 s e a l e d modifier cant 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 implementationthe 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 o v e r r i d eas 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:
a b s t r a c tc l a s sA b s t r a c t C l a s s { p u b l i ci n ti = 5 ; p u b l i cv o i dM e t h o d ( ) { C o n s o l e . W r i t e L i n e ( " A b s t r a c t C l a s s : : M e t h o d ( ) i = " + i . T o S t r i n g ( ) ) ; } / /c a n ' th a v ea ni m p l e m e n t a t i o n : p u b l i ca b s t r a c tv o i dA b s t r a c t M e t h o d ( ) ; / /t h ep r o p e r t yc a n n o th a v ea ni m p l e m e n t a t i o ne i t h e r : p u b l i ca b s t r a c ti n tI { g e t ; }
c l a s sC o n c r e t e C l a s s:A b s t r a c t C l a s s { / /b e c a u s et h e r e ' sa na b s t r a c tm e t h o di nt h ei n h e r i t e dc l a s s , / /w eh a v et op r o v i d et h ei m p l e m e n t a t i o nh e r e . N o t et h a tw em u s t
or that the parameter being passed as a reference could not be modified by the method:
v o i dF o o ( c o n s ti n t &i ) ;
Happily, C# treats the keyword c o n s t 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:
c o n s ti n tf o o = 1 0 ; i n tb a r = 1 6 ;
Example:
c l a s sH a s C o n s t F i e l d { p u b l i cH a s C o n s t F i e l d ( ) ;/ /c a n ' td o :{ i = 3 ; } p u b l i cc o n s ti n ti = 1 ; p u b l i ci n tI { g e t{ r e t u r ni ; } / /c a n ' td o :s e t{ i = 5 ; } }
} H a s C o n s t F i e l dh c f = n e wH a s C o n s t F i e l d ( ) ; / /c a n ' td o :h c f . i = 3 ;
The r e a d o n l ykeyword is similar to c o n s t , 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):
p u b l i cc l a s sR e a d O n l y T e s t { c l a s sM y C l a s s { p u b l i ci n tx ; p u b l i cr e a d o n l yi n ty=2 5 ;/ /I n i t i a l i z ear e a d o n l yf i e l d p u b l i cr e a d o n l yi n tz ; p u b l i cM y C l a s s ( ) { z=2 4 ; / /I n i t i a l i z ear e a d o n l yi n s t a n c ef i e l d } p u b l i cM y C l a s s ( i n tp 1 ,i n tp 2 ,i n tp 3 ) { x=p 1 ; y=p 2 ; z=p 3 ; }
extern
The e x t e r nkeyword is basically used just for non-C# function calls, which also requires:
u s i n gS y s t e m . R u n t i m e . I n t e r o p S e r v i c e s ;
and is used in conjunction with the D l l I m p o r t 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:
[ D l l I m p o r t ( " U s e r 3 2 . d l l " ) ] p u b l i cs t a t i ce x t e r ni n tM e s s a g e B o x ( i n th ,s t r i n gm ,s t r i n gc ,i n tt y p e ) ; M e s s a g e B o x ( 0 ," T e s t " ," M yM e s s a g eB o x " ,0 ) ;
internal
The i n t e r n a lkeyword 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 i n t e r n a l 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 p r o t e c t e d and p r i v a t e keywords, which restrict access of members to derived classes and the class methods themselves, respectively. Also, all i n t e r n a l members are treated as public within the scope of the assembly. The only exception to this is the p r o t e c t e di n t e r n a l 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 dont tamper with the value or access the function), while also making the method or field inaccessible outside of the assembly. Example:
/ /T h i sc l a s si so n l yv i s i b l et ot h i sa s s e m b l y . i n t e r n a lc l a s sI n t e r n a l C l a s s { } c l a s sI n t e r n a l T e s t C l a s s { / /t h i sf i e l di sv i s i b l eo n l yw i t h i nt h i sa s s e m b l y . i n t e r n a li n ti = 2 ; / /t h i sm e t h o di sv i s i b l eo n l yw i t h i nt h i sa s s e m b l y . i n t e r n a lv o i dI n t e r n a l M e t h o d ( ) { C o n s o l e . W r i t e L i n e ( " I n t e r n a l M e t h o d " ) ; } / /t h i sp r o t e c t e dm e t h o dc a no n l yb ei n v o k e db yd e r i v e dc l a s s e s . i n t e r n a lp r o t e c t e dv o i dI n t e r n a l P r o t e c t e d M e t h o d ( ) { C o n s o l e . W r i t e L i n e ( " I n t e r n a l P r o t e c t e d M e t h o d " ) ; } / /t h i sa t t r i b u t ei sv i s i b l eo n l yw i t h i nt h i sa s s e m b l y . i n t e r n a li n tI { g e t{ r e t u r ni ; } s e t{ i = v a l u e ; }
I n t e r n a l T e s t C l a s si t c = n e wI n t e r n a l T e s t C l a s s ( ) ; i t c . I + = 5 ; C o n s o l e . W r i t e L i n e ( " I = " + i t c . i . T o S t r i n g ( ) ) ; i t c . I n t e r n a l M e t h o d ( ) ;
In this example, the N o n V i r t u a l M e t h o d 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:
c l a s sV i r t u a l C l a s s { p u b l i cv i r t u a lv o i dV i r t u a l M e t h o d ( )
{ } }
C o n s o l e . W r i t e L i n e ( " V i r t u a l C l a s s : V i r t u a l M e t h o d " ) ;
resulting in:
O v e r r i d e C l a s s B : V i r t u a l M e t h o d O v e r r i d e C l a s s A : V i r t u a l M e t h o d V i r t u a l C l a s s : V i r t u a l M e t h o d O v e r r i d e C l a s s B : V i r t u a l M e t h o d O v e r r i d e C l a s s A : V i r t u a l M e t h o d V i r t u a l C l a s s : V i r t u a l M e t h o d O v e r r i d e C l a s s B : V i r t u a l M e t h o d O v e r r i d e C l a s s A : V i r t u a l M e t h o d V i r t u a l C l a s s : V i r t u a l M e t h o d
Now compare the above class definition with the following: Example 2C:
c l a s sN e w B a s e C l a s s { p u b l i cv i r t u a lv o i dV i r t u a l M e t h o d ( ) { C o n s o l e . W r i t e L i n e ( " N e w B a s e C l a s s : V i r t u a l M e t h o d " ) ; } } c l a s sN e w C l a s s A:N e w B a s e C l a s s { p u b l i cn e wv o i dV i r t u a l M e t h o d ( ) { C o n s o l e . W r i t e L i n e ( " N e w C l a s s A : V i r t u a l M e t h o d " ) ; b a s e . V i r t u a l M e t h o d ( ) ; } }
And note the use of the n e wmodifier. When the following code is run: Example 2D:
N e w C l a s s Bn c b = n e wN e w C l a s s B ( ) ; n c b . V i r t u a l M e t h o d ( ) ; ( ( N e w C l a s s A ) n c b ) . V i r t u a l M e t h o d ( ) ; ( ( N e w B a s e C l a s s ) n c b ) . V i r t u a l M e t h o d ( ) ;
we get:
O v e r r i d e C l a s s B : V i r t u a l M e t h o d O v e r r i d e C l a s s A : V i r t u a l M e t h o d V i r t u a l C l a s s : V i r t u a l M e t h o d O v e r r i d e C l a s s A : V i r t u a l M e t h o d V i r t u a l C l a s s : V i r t u a l M e t h o d V i r t u a l C l a s s : V i r t u a l M e t h o d
Now, the cast allows us to access the specific base class member, because the derived class provides a new specialization, meaning that it doesnt 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 n e w modifier is not necessary. Also note that a virtual member cannot be private, because it is impossible to override a private memberit is private to the class that implements it. One final pointinspecting the resulting assembly code shows that there is no difference in performance between invoking members that are modified with the n e w keyword vs. the o v e r r i d e keyword.
c l a s sP P P { p r i v a t ei n ta = 0 ; p u b l i ci n tA { g e t{ r e t u r na ; } s e t{ a = v a l u e ; } } p r o t e c t e di n tA 2 { g e t{ r e t u r na * 2 ; } s e t{ a = v a l u e / 2 ; } } p u b l i ci n tG e t A ( ){ r e t u r na ; } p r o t e c t e di n tG e t A 2 ( ){ r e t u r na * 2 ; } p r i v a t ev o i dS e t A 2 ( i n ta 2 ){ a = a 2 / 2 ; } }
sealed
The s e a l e dmodifier 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 shouldnt have been sealed by the designers at Microsoft, so be careful when considering whether to seal your own classes. Similar to using the p u b l i c ,p r o t e c t e d and p r i v a t e modifiers, using the s e a l e dmodifier 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 s t a t i c 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 s t a t i ckeyword is a mechanism for providing global functions and variables. For example:
c l a s sS t a t i c C l a s s { p u b l i cs t a t i ci n ta = 0 ; p u b l i ci n tA { g e t{ r e t u r na ; } s e t{ a = v a l u e ; } }
Outputs:
S c 2 . A = 1 0 S c 1 . A = 2 0 S c 2 . A = 2 0
Illustrating how even though a was set using instance s c 1 , it affected instance s 1 , 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 v o l a t i l emodifier ensures that the compiler generates code that always reads from the fields memory location (as opposed to optimizing by perhaps re-using a register that was previously loaded with the fields 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 v o i d keyword modifies a method, indicating that it does not have a return value. Unlike C++, you cannot use the v o i dkeyword 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.
License
This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below. A list of licenses authors might use can be found here
Marc Clifton
United States
Marc is the creator of two open source projets, MyXaml, a declarative (XML) instantiation engine and the Advanced Unit Testing framework, and Interacx, a commercial n-tier RAD application suite. Visit his website, [Link], where you will find many of his articles and his blog. Marc lives in Philmont, NY.