Reintroducing C#:-A Detailed Look at the Language We All Know - Expert C# 5.0: with .NET 4.5 Framework (2013)

Expert C# 5.0: with .NET 4.5 Framework (2013)

CHAPTER 1

images

Reintroducing C#:-A Detailed Look at the Language We All Know

This chapter will discuss the basics of the C# language. It begins with an example of a square number generator program to explain the basic structure of a C# program, how the C# compiles a C# program, and then explains Just-in-Time compilation. You will learn about the lexical element of the C# language, different types such as value and reference types, variables, parameters, and statements, and about the interface, enum, and delegate classes.

Square Number Using the C#

Listing 1-1 shows a simple program that calculates the square of a given number and displays the squared number as output.

Listing 1-1. Square Number Program

using System; /* importing namespace */

namespace Ch01 /* namespace declaration */
{
class Program /* class declaration*/
{
static void Main(string[] args) /* method declaration */
{
PowerGenerator pg = new PowerGenerator();
pg.ProcessPower();
} /* end of method declaration */
} /* end of class declaration */

public class PowerGenerator
{
const int limit = 3; /* constant declaration */
const string
original = "Original number",
square = "Square number";
public void ProcessPower()
{
Console.WriteLine("{0,16}{1,20}",
original, square); /* statement*/
for (int i = 0; i <= limit; ++i) /* iteration statement*/
{
Console.Write("{0,10}{1,20}\n", i, Math.Pow(i, 2));
}
}
}
} /* end of namespace declaration */

A C# program consists of statements, and each of these statements executes sequentially. In Listing 1-1, the Pow method from the Math class processes the square of a number, and the Write method from the Console class displays the processed square number on the console as output. WhenListing 1-1 is compiled using the C# compiler csc.exe and executes the executable, it will produce the output:

Original number Square number
0 0
1 1
2 4
3 9

Listing 1-1 contains a class called a program inside the namespace Ch01. A namespace is used to organize classes, and classes are used to organize a group of function members, which is called a method. A method is a block of statement defined inside curly braces {}, such as {statement list}inside a class, for example:

static void Main( string[] args ){……}

An int literal 3 and the string literals “Original number” and “Square number” are used in the program to define three variables. In Listing 1-1, the iteration statement for is used to iterate through the processing. A local variable i is declared in the for loop as a loop variable. The following section will explore the compilation process of a C# program.

Compilation of a C# Program

The C# compiler compiles the C# source code into the module, which is finally converted into the assembly. The assembly contains the Intermediate Language (IL) code along with the metadata information about the assembly. All of this happens in the compile time of the program. Figure 1-1 demonstrates the compilation process of a C# program.

images

Figure 1-1. The compilation process of a C# program

The common language runtime (CLR) works with the assembly. It loads the assembly and converts it into the native code to execute the assembly, as demonstrated in Figure 1-1.

When the CLR executes a program, it executes the program method by method, and before it executes any method (unless the method has already been Jitted), the JITTER needs to convert it into the native code. The compiler refers to the Just-in-Time (JIT) compiler of the CLR, which is responsible for compiling the IL code into the native instructions for execution. The CLR retrieves the appropriate metadata information of the method from the assembly, extracts the IL code for the method, and allocates a block of memory onto the Heap, where the JITTER will store the JITTED native code for that method. The following section will explore the Jitting process to convert IL code into the native code.

Jitting a C# Program

Figure 1-1 shows that in runtime the JIT compiler, which is part of the CLR, compiles the IL code into the native code. Let’s analyze Listing 1-1 to see how the IL code of the method is converted into the native code.

1. Step 1: When the CLR loads the assembly produced from Listing 1-1, the methods of the Program class and PowerGenerator class will not yet be Jitted by the JITTER. In Figure 1-2, you can see that the Main method of the Program class and ProcessPower method of the PowerGenerator class has not yet been JITTED, as shown by its Not JITTED yet status. Sometime later, the JITTER converts the IL code of the Main method into the native code, and the status of the method description table of the Main method shows the JITTED address stored in the Heap. The contents of this address will contain the JITTED native code for the Main method.

2. Step 2: The JITTER still has not generated the native code for the ProcessPower method because the status of the ProcessPower method shows Not JITTED yet as the status and the status of the ProcessPower method shows NONE for JIT status, as described in Figure 1-2.

images

Figure 1-2. Jitting process of the assembly in Listing 1-1

3. Step 3: Sometime later, the JITTER converts the IL code of the ProcessPower method into the native code and the native code is stored in the Heap. The method description table of the ProcessPower method in Figure 1-2 shows the address of the native code for the ProcessPower method. The contents of the native code that are stored in the Heap, as shown in Figure 1-2, were extracted using the following commands:

!u -n 004c0050
!u -n 004c00e8

images Note: The IL code shown in Figure 1-1 was decompiled using the ildasm.exe. The windbg.exe was used to explore different runtime information while the executable from Listing 1-1 executes. You can explore more detail about the ildasm.exe and windbg.exe tools in Chapter 15. In Figure 1-2, a different debugging command used, which is also discussed in Chapter 15. In addition to the ildasm.exe and windbg.exe tools, the .NET Reflector tool is used to explore the IL/C# code for the assembly.

Understanding the C# Language

This section explores the C# language. You will learn the syntax and usage of the identifiers, keywords, and literals. You will explore the different types used in C#, such as value type and reference type, how to declare a variable, and how many different types of variables can be used in a program. You will also learn about different types of statements that can be declared in C#, and, finally, you will learn about classes, types of classes, constructors, fields, and methods.

Identifiers

Identifiers are names used in the application to identify a namespace, class, method, variable, delegate, interface, and so on. Figure 1-3 demonstrates the possible forms of the identifiers.

images

Figure 1-3. Possible forms of the identifier declaration

Figure 1-3 demonstrates the possible combination of the characters and digits used to define an identifier.

· An identifier is composed of the Unicode characters or it can start with an underscore character or characters (_) along with other characters, such as _identifier or _iden77tifier, or \u005F\u005FIdentifier (compiled as __Identifier).

· An identifier can start with the at sign (@) as its prefix, such as @int (as used in Listing 1-2), and it is referred to as the verbatim identifier. To use a keyword as an identifier, the @ needs to be the prefix for the keyword.

· Unicode escape is used to define an identifier, such as “cl\u0061ss,” when the C# compiler compiles “cl\u0061ss” as a class.

Listing 1-2 shows the usage of the identifier in a program.

Listing 1-2. Example of the Identifier

using System;

/* Ch01 is the identifier to name the namespace*/
namespace Ch01
{
/* Program is the identifier to name the class */
class Program
{
/* Main is the identifier to name the method */
static void Main(string[] args)
{
/* a and _a is the identifier to name the variable */
int a = 10, _a = 20;
/* Verbatim identifier - start with an @ prefix */
int @int = 10;

Console.WriteLine("{0}\t{1}\t{2}", a,_a, @int);
}
}
}

This program will produce the output:

10 20 10

The decompiled IL code (decompiled using the ildasm.exe) of Listing 1-2 shows how the variable names, such as a, _a, and @int, are compiled by the C# compiler:

.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
.maxstack 4
.locals init (
[0] int32 a, /* a compiled as a */
[1] int32 _a, /* _a compiled as _a */
[2] int32 int) /* @int compiled as int */
/* Code removed */
}

The IL code shows that the variables a and _a are compiled as they are defined in the C# source code, but the @int is compiled as int, where the C# compiler eliminates the @ character from the verbatim identifier.

Keywords

A keyword is a sequence of characters, such as identifiers, but it is used as reserved by the C# compiler except that it can be used as the identifier when prefixed with the @ character. The C# language supports the @ character to prefix a variable name, but it is not common practice to use it.Listing 1-3 shows the usage of the keywords in a method.

Listing 1-3. Example of the Keywords

static void Main(string[] args)
{
int a = 100, @int = 100; /* int is keyword and @int used
* as identifier*/
try { /* try is keyword */
Console.Write(a / @int);
}
catch {
throw;
} /* catch and throw is keyword */
}

In Listing 1-3, the int keyword is prefixed with @, which makes int the identifier. The decompiled IL code (decompiled using the ildasm.exe) of Listing 1-3 shows how the C# compiler compiles keywords:

.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
.maxstack 2
.locals init (
[0] int32 a, /* Code removed */
[1] int32 int) /* @int translates as int */
/* Code removed */
}

The IL code shows that the variable a is compiled as it is defined in the C# source code, but the @int is compiled as int, and the C# compiler eliminates the @ character from the variable name. Table 1-1 lists the keywords available for use in C#.

images

images

The C# also has a few contextual keywords besides the keywords shown in Table 1-1. The following section discusses the contextual keywords in C#.

Contextual Keywords

A contextual keyword is not a reserved word in C#, but it is used to provide specific meaning in the code. Table 1-2 shows the list of contextual keywords available in C#.

images

Literals

In C#, a literal is used to represent the value in source code, or a literal can be a piece of data embedded into the source code, such as:

string book = "Expert C# 5.0"; /* "Expert C# 5.0" represents a string
* literal in source code */
int chapters = 14; /* 14 is the int literal used for the
* chapters variable */

Table 1-3 lists six types of literal used in C# language.

images

Boolean Literal

Two types of Boolean literal values can be used in C#:

bool myBoolAsTrue = true;
bool myBoolAsFalse = false;

Integer Literal

Integer literals are use to represent the values of int, uint, long, and ulong:

long one = 30l; /* long literal 30l with suffix l */
uint two = 0x2u; /* uint literal 0x2u in Hexadecimal
* format (starts with 0x) */
int three = 3; /* int literal 3 */
ulong hundred = 100; /* ulong literal 100 which has more
* than one decimal digit */

Figure 1-4 demonstrates the possible forms of the integer literals.

images

Figure 1-4. Possible forms of the integer literals declaration

From Figure 1-4, you can see that integer literals can be either a decimal integer literal or a hexadecimal integer literal. These are discussed in the next sections.

Decimal Integer Literals

A decimal integer literal starts with one or more decimal digits (depending on the type size where it is going to be stored) along with one of the integer type suffixes, for example, 7, 77, 77u, 77l. As Figure 1-4 demonstrates, an integer type suffix is optional to define the decimal integer literals.

Hexadecimal Integer literals

A hexadecimal integer literal starts with 0x to denote it as the hexadecimal format along with one or more (depending on the type size where it is going to be used) hex digits along with one of the integer type suffixes, for example, 0x7, 0x77, 0x77l. As Figure 1-4 demonstrates, the integer type suffix is optional to define hexadecimal integer literals.

Real Literal

Real literals are use to represent the values of float, double, and decimal:

double one = 30.1; /* double literal 30.1 */
float two = 30; /* float literal 30*/
double three = 30.1e+1; /* double literal with exponent
* part e+1, 30.1e+1 */
double hundred = 100.12E-1; /* double literal with E-1, 100.12E-1 */

The possible forms of the real literals are demonstrated in Figure 1-5.

images

Figure 1-5. Possible forms of the real literal declaration

Character Literal

A character literal represents a single character and consists of a character in single quotes:

'a character'

For example:

'M'
'R'

When declaring a character literal that contains a backslash character (\), it must be followed by one of the escape sequence characters, as shown in Table 1-4.

images

For example:

/* declare a char variable */
char charLiteral;

/* assign variety of the escape characters on multiple lines.
* Each of the escape character will produce respective output as
* describes on the above table.*/

charLiteral = '\''; /* \ character follows by ' */
charLiteral = '\"'; /* \ character follows by " */
charLiteral = '\\'; /* \ character follows by \ */
charLiteral = '\0'; /* \ character follows by 0 */
charLiteral = '\a'; /* \ character follows by a */
charLiteral = '\b'; /* \ character follows by b */
charLiteral = '\f'; /* \ character follows by f */
charLiteral = '\n'; /* \ character follows by n */
charLiteral = '\r'; /* \ character follows by r */
charLiteral = '\t'; /* \ character follows by t */
charLiteral = '\x4'; /* \ character follows by x */
charLiteral = '\v'; /* \ character follows by v */

/* If you declare a character literal as shows below, the C# compiler
* shows compile time error as \ does not follows any escape character. */

//char charLiteral = '\';

Null Literal

In C#, the null literal is used for the reference type, and it cannot be used in the value type unless the value type is used as a nullable type. Listing 1-4 shows the use of the null literal in a program.

Listing 1-4. Example of the Null Literal

using System;
namespace Ch01
{
class Program
{
static void Main(string[] args)
{
Book aBook = null; /* Reference type can be set with
* null literal */
int chapters = null; /* Compiler error for value type
* when set with null literal*/
Nullable<int> pages = null; /* null can be set in value type
* when it is a type of Nullable */
}
}
class Book { }
}

String Literal

A string literal is used to represent a series of characters in the source code. The C# compiler supports two forms of the string literals: regular string literals and verbatim string literals.

A string literal is used in source code as shown in the code:

string address = "Zero Point, Prometheus"; /* Regular string literal */
string source = @"J:\Book\ExpertC#2012\Ch01"; /* Verbatim string literal
* with @*/
string bookName = @"Expert C# 5.0
: with the .NET 4.5 Framework"; /* Verbatim string literal
* in multiple lines */
string regularString = "One\tTwo"; /* One Two*/
string verbatimString = @"One\tTwo"; /* One\tTwo*/

Figure 1-6 shows the possible forms of the string literals.

images

Figure 1-6. Possible forms of the string literals declaration

Figure 1-6 demonstrates that a regular string literal character needs to be declared inside double quote marks (""), and inside the double-quoted string literal it is not possible to use a character, such as " ( U+0022 - Unicode representation of "), \ (U+005c – Unicode representation of the \ ), or a new line character, such as CR (carriage return) or LF (line feed).

When declaring a string literal that contains a backslash character in regular string literal, the character must be followed by one of the ', ", \, 0, a, b, f, n, r, t, x, v characters, which is demonstrated in Table 1-4. For example:

/* declare a string variable */
string stringLiteral;

/* assign variety of the escape characters on multiple lines.
* Each of the escape character will produce respective output as
* describes on the Table 1-4.*/

stringLiteral = "A String Literal with \' "; /* \ character follows by ' */
stringLiteral = "A String Literal with \" "; /* \ character follows by " */
stringLiteral = "A String Literal with \\ "; /* \ character follows by \ */
stringLiteral = "A String Literal with \0 "; /* \ character follows by 0 */
stringLiteral = "A String Literal with \a "; /* \ character follows by a */
stringLiteral = "A String Literal with \b "; /* \ character follows by b */
stringLiteral = "A String Literal with \f "; /* \ character follows by f */
stringLiteral = "A String Literal with \n "; /* \ character follows by n */
stringLiteral = "A String Literal with \r "; /* \ character follows by r */
stringLiteral = "A String Literal with \t "; /* \ character follows by t */
stringLiteral = "A String Literal with \x4 ";/* \ character follows by x */
stringLiteral = "A String Literal with \v "; /* \ character follows by v */

/* If you declare a string literal as shows below, the C# compiler
* shows compile time error as \ does not follows any escape character. */

//stringLiteral= "A String Literal with \ "; /* Compiler error */

Comments

C# language supports comments in the source code in the following forms:

· Single line: Single line comment starts with // followed by characters except for the new line character.

· Multiline: Multiline comment starts with /* and ends with */. In between the /* and */, it contains characters that are treated as comments by the C# compiler.

For example:

int daysInStandardYear = 365; // When the year is not a leap year.
int daysInLeapYear = 366; /* When the year is
* a leap year. */

The C# compiler skips all the comments used in the C# source code while it compiles the source into the IL code. For example, when the C# compiler compiles the following program, it will eliminate comments used in the program when compiled into IL code:

namespace Ch01
{
class Program
{
static void Main(string[] args)
{
int daysInStandardYear = 365; // When the year is not a leap year.
int daysInLeapYear = 366; /* When the year is
* a leap year. */
}
}
}

The decompiled (decompiled using the .NET Reflector tool) IL for this program is:

.class private auto ansi beforefieldinit Program extends [mscorlib]System.Object
{
.method public hidebysig specialname rtspecialname instance
void .ctor() cil managed
{
.maxstack 8
L_0000: ldarg.0
L_0001: call instance void [mscorlib]System.Object::.ctor()
L_0006: ret
}

.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
.maxstack 1
.locals init (
[0] int32 daysInStandardYear,
[1] int32 daysInLeapYear)
L_0000: nop
L_0001: ldc.i4 0x16d
L_0006: stloc.0
L_0007: ldc.i4 0x16e
L_000c: stloc.1
L_000d: ret
}
}

The decompiled IL code shows that the C# eliminates the comments used in the C# source code while it is compiled into the IL code.

Types

In C#, types are divided into two main categories: value types and reference types. These are discussed in the sections that follow.

Value Types

The variables of the value types directly contain their value. Listing 1-5 shows an example of value type int (10), struct (Book), and enum (Planets). Listing 1-5 shows how we can determine the usage of the value type in a program.

Listing 1-5. Example of Value Types

using System;
namespace Ch01
{
class Program
{
static void Main(string[] args)
{
int a = 10; /* int type */
Book book = new Book(); /* struct type */
Planets planets = Planets.Earth; /* enum type */
}
}

struct Book { } /* struct type declaration */
enum Planets { Earth = 0 } /* enum type declaration*/
}

Figure 1-7 demonstrates the possible different value types.

images

Figure 1-7. Possible forms of the value types declaration

Figure 1-7 demonstrates that in C# the value type is categorized into two main categories, such as struct and enum. The struct type is further divided into simple and nullable types and so on.

Simple Types

Tables 1-5 through 1-9 list the different types of integrals, their ranges, and the precision information.

images

images

images

images

images

Default Constructor of Value Types

The default constructor is the value type implicitly declared by a public parameterless instance constructor, which sets the default value for that value type. Table 1-10 shows the default values for the different value types.

images

Reference Types

In C#, the reference type is either the class type, an interface type, an array type, or a delegate type. Listing 1-6 shows the usage of these reference types.

Listing 1-6. Example of the Reference Types

using System;
namespace Ch01
{
class Program
{
static void Main(string[] args)
{
IBook book = new Book(); /* book is an instance of the Book */
}
}

interface IBook { }

class Book : IBook { }
}

Figure 1-8 shows the possible different reference types.

images

Figure 1-8. Possible forms of the reference type declaration

The value of the reference types is the instance of that type, which is known as its object. Table 1-11 lists the different reference types that are shown in Figure 1-8.

images

The This Keyword and Reference Type

The this keyword is a special keyword used in a class. It is a reference to the current instance of a type. The this keyword cannot be used in any static function member of a type since the static members are not part of an instance. The this keyword can be used in the following class members:

· Instance constructors

· Instance methods

· Instance accessors of properties and indexers

Listing 1-7 demonstrates the use of the this keyword.

Listing 1-7. Example of the Usage of the This Keyword

using System;
namespace Ch01
{
class Program
{
static void Main(string[] args)
{
AClass aClass = new AClass();
Console.WriteLine(aClass.MethodA(10));
Console.ReadLine();
}
}

public class AClass
{
public int MethodA(int a) { return a * MethodB(); }
public int MethodB() { return 10; }
}
}

Listing 1-7 produces the output:

100

The body of the MethodA from the AClass can be writing as:

public int MethodA(int a)
{
return a * this.MethodB(); /* this refers to the instance of the
* AClass in runtime */
}

In this version of the MethodA, the this keyword is used to access MethodB. It is the same for MethodB, but the Main method of the Program class cannot use the this keyword because it is a static member of the Program class.

In Listing 1-7, the this keyword has not been used directly because the C# compiler can take care of it without including it in the C# source code. Let’s analyze the decompiled IL code from Listing 1-7:

.method public hidebysig instance int32 MethodA(int32 a) cil managed
{
.maxstack 2
.locals init (
[0] int32 CS$1$0000)
L_0000: nop
L_0001: ldarg.1

/* Points to the this parameter whose value passed by the CLR
* and it will be explored in the Figure 1-9.*/
L_0002: ldarg.0

L_0003: call instance int32 Ch01.AClass::MethodB()

L_0008: mul
L_0009: stloc.0
L_000a: br.s L_000c
L_000c: ldloc.0
L_000d: ret
}

The decompiled IL code shows how the CLR passed the value of the this keyword as part of the method call. In L_0002 the ldarg.0 IL instruction loads the value of the first argument passed when the MethodA is called. Figure 1-9 illustrates in detail the use of the this keyword.

When the CLR calls MethodA from the Main method of the Program class and MethodB from the MethodA of the AClass in Listing 1-7, the CLR passes an extra argument to the method (which belongs to the instance of the type) as input for the this parameter. In this circumstance, the keyword this will refer to the object (instance of the AClass, instantiated in the Main method). Figure 1-9 demonstrates how the CLR passes value for the this parameter when it calls MethodA and MethodB.

images

Figure 1-9. Usage of the this keyword in runtime

Figure 1-9 shows that MethodA and MethodB have an extra parameter this in the PARAMETERS section of the Method state description table for MethodA and MethodB. This extra parameter is filled with the instance of AClass when the CLR calls MethodA from the Main method and MethodB from the MethodA. The thiskeyword is only visible in the instance method.

Finally, the this keyword can also be used:

· To distinguish between class members and local variables or parameters in a class

· When calling a method, as an actual parameter, as shown in Figure 1-9

images dumpobj: Command used in the windbg.exe program to explore the status of an object stored onto the Heap.

Array

Arrays are data structures that store collections of data and allow access to the elements by using simple index operations. Some of the characterizations of the C# array are:

· C# arrays are zero indexed; the array index starts at zero.

· All of the array elements must be of the same type.

· Array elements can be of any type, including an array type.

· An array can be a single-dimensional array or a multidimensional array.

· Array types are reference types derived from the abstract base type System.Array.

In C#, arrays can be one dimensional, multidimensional, rectangular, variable length, or associative. The next section explores these types of arrays.

One-Dimensional Arrays

One-dimensional arrays are declared by stating their element type followed by empty square brackets, as shown in the code:

int[] arr1;
char[] characters = { 'a', 'b', 'c' };
double[] arr3 = new double[5];

string[] arr4 = new string[]
{
"Galactic Centre", "Great Rift", "Interstellar Dust"
};

Console.WriteLine(arr1.Length); /* Compile time error:
* unassigned variable */
Console.WriteLine(characters.Length); /* 3 */
Console.WriteLine(arr3.GetLength(0)); /* 5 */

Multidimensional Arrays

Multidimensional arrays can be jagged or rectangular. Jagged arrays hold reference to other arrays:

double [][] arr = new double [2][];
arr[0] = new double [] {1.3, 2.4, 4.5, 6.6};
arr[1] = new double [] {6.7, 1.1, 3.5};

Console.WriteLine(arr[0].Length); /* 4 */
Console.WriteLine(arr[1].Length); /* 3 */
Console.WriteLine(arr.Rank); /* 1 (1 dimension) */
Console.WriteLine(arr.GetLength(0)); /* 2 */
Console.WriteLine(arr.GetLength(1)); /* Runtime error: Index was outside
* the bounds of the array */

Rectangular arrays are more compact and efficient for indexing:

double [,] a = new double[2, 3];
string[, ,] b = new string[3, 2, 4];
double[,] arr =
{
{ 1.3, 2.4, 4.5 },
{ 6.6, 1.2, 3.2 }
};
Console.WriteLine(arr.Length); /* 6 */
Console.WriteLine(arr.Rank); /* 2 (2 dimensions) */
Console.WriteLine(arr.GetLength(0)); /* 2 */
Console.WriteLine(arr.GetLength(1)); /* 3 */

Variable-Length Arrays

Jagged or rectangular arrays have fixed lengths after declaration. The ArrayList (discussed in detail in Chapter 11) class in the namespace System.Collections provides arrays of variable length, as shown in Listing 1-8.

Listing 1-8. An Example of the Variable Length Arrays

using System;
using System.Collections;

namespace Ch01
{
class MainClass
{
static void Main(string[] args)
{
ArrayList al = new ArrayList();
al.Add("C#");
Console.WriteLine(al.Count); /* 1 */
Console.WriteLine(al[0]); /* C# */
}
}
}

This program will produce the output:

1
C#

Associative Arrays

Arrays can be indexed by strings if they are created by the class Hashtable (discussed in detail in Chapter 11) in the namespace System.Collections, as shown in Listing 1-9.

Listing 1-9. Example of the Associative Arrays

using System;
using System.Collections;
namespace Ch01
{
class MainClass
{
static void Main(string[] args)
{
Hashtable htArray = new Hashtable();
htArray["1"] = "Milky way";
htArray["2"] = "Galaxy";
Console.WriteLine(htArray.Count); /* 2 */
Console.WriteLine(htArray["1"]); /* Milky way */
Console.WriteLine(htArray["2"]); /* Galaxy */
}
}
}

This program will produce the output:

2
Milky way
Galaxy

Variables

In C#, variables represent the storage locations that contain the value. The type of value can be stored in the variable determined by the variable type. For example:

/* a string type variable */
string bookName = " Expert C# 5.0: with the .NET 4.5 Framework";
/* a int type variable */
int publishedYear = 2012;

The C# compiler guarantees that values stored in variables are always of the appropriate type as it defined.

Default Values for the Variables

All the type instances have a default value. Table 1-12 shows the default values for the different types.

images

Listing 1-10 shows the usage of the default keyword, which is used in C# to return the default value of a type.

Listing 1-10. Example of the Default Values for Different Types

using System;
namespace Ch01
{
class Program
{
static void Main(string[] args)
{
Book book = default(Book); /* null */
int i = default(int); /* 0 */
float f = default(float); /* 0.0 */
char c = default(char); /* '\0' */
bool b = default(bool); /* false */
Planets p = default(Planets); /* Earth */
}
}

class Book { } /* a reference type Book declaration */
enum Planets { Earth=0 } /* enum declaration */
}

Listing 1-10 shows how you can use the default keyword to initialize the default values for the type, otherwise you can explicitly set the default value for the type when it is initialized.

Variable Storage

There are two kinds of variable storage used in the C#: the Stack and the Heap. These are discussed in the following sections.

Stack

The Stack is used to store local variables and parameters and other information. Let’s see how the CLR maintains the Stack when it executes the Main method, as shown in Listing 1-11.

Listing 1-11. Example of the Stack and Heap

using System;
namespace Ch01
{
class Program
{
static void Main(string[] args)
{
Converter converter = new Converter();
converter.ConvertAndIncrease(10);
}
}

public class Converter
{
public int ConvertAndIncrease(int baseValue)
{
int increaseFactor = 10;
return baseValue + increaseFactor;
}
}
}

When the CLR calls the ConvertAndIncrease method of the converter object, it will create a block of memory to store arguments, local variables, and others, which it refers to as the Stack for that method. Figure 1-10 shows the Stack information for the Main method while the CLR executes theConvertAndIncrease method.

images

Figure 1-10. Stack state of the Main method

Heap

The C# stores objects of the reference type into the Heap (i.e., when you instantiate an instance of a reference type, the CLR allocates that instance in the Heap and returns the reference of that object). When the program in Listing 1-11 is executed by the CLR, it will instantiate an instance of the Converter class onto the Heap and pass the reference of that instance back to the Main method Stack, as demonstrated in Figure 1-11.

images

Figure 1-11. Heap state when instantiates an instance of the reference type

The Stack and the Heap are discussed in greater detail in Chapter 2.

Types of Variables

C# defines seven categories of variables: static variables, instance variables, array elements, value parameters, reference parameters, output parameters, and local or global variables. The following sections explore these variables in detail.

Static Variables

The static variables are declared with the static keyword. It comes to life before execution of the static constructor for the type in which it is defined. The life of the static variable loses its existence when the associated application domain loses its existence. The initial value of a static variable is the default value of the variable’s type. Listing 1-12 shows the usage of the static variables in a program.

Listing 1-12. Example of the Static Variables

using System;
namespace Ch01
{
class Program
{
public static int X=100; /* Static variable */

static void Main(string[] args)
{
Console.Write("{0}\t", X); /* 100 */
Program.X = 200; /* This change affect globally */
Console.Write("{0}\t", X); /* 200 */
Show();
}

static void Show()
{
Console.Write("{0}\t", Program.X); /* 200 */
}
}
}

This program will produce the output:

100 200 200

If you debug Listing 1-12 using the windbg.exe tool, you will be able to see that the scope of the static variable is class wide. It does not require the compiler to instantiate an instance of the containing class, for example, X variable of the Program class will be accessible without instantiating theProgram class:

0:000> !name2ee Ch01.exe Ch01.Program
Module: 00232e94
Assembly: Ch01.exe
Token: 02000002
MethodTable: 00233760
EEClass: 00231264 /* This address used to explore about the
* static class such as Program */
Name: Ch01.Program

Let’s look at the details of the static variable of the Program class using the EEClass address of the program:

0:000> !dumpclass 00231264
Class Name: Ch01.Program
mdToken: 02000002
File: J:\Book\ExpertC#2012\SourceCode\BookExamples\Ch01\bin\Debug\Ch01.exe
Parent Class: 55094f7c
Module: 00232e94
Method Table: 00233760
Vtable Slots: 4
Total Method Slots: 6
Class Attributes: 100000
Transparency: Critical
NumInstanceFields: 0
NumStaticFields: 1
MT Field Offset Type VT Attr Value Name
5548cfc8 4000001 20 System.Int32 1 static 100 X

The output shows that a class is not required to instantiate access to its static variables.

Instance Variables

A field declared without the static modifier is called an instance variable. Listing 1-13 shows an example of the instance variable.

Listing 1-13. Example of the Instance Variables

using System;
namespace Ch01
{
class Program
{
static void Main(string[] args)
{
AClass anObject = new AClass();
Console.ReadLine();
}
}
public class AClass
{
public int X;
public AClass()
{
Console.WriteLine("Initial value of the X :{0}", X);
X = 100;
Console.WriteLine("Updated value of the X :{0}", X);
MethodA();
}
public void MethodA() { }
}
}

This program will produce the output:

Initial value of the X :0
Updated value of the X :100

Instance Variables in Classes

An instance variable of a class comes to life when a new instance of that class is instantiated. In addition, it will no longer exist when there are no references to that instance and the instance’s destructor (if any) has executed.

Instance Variables in Structs

An instance variable of a struct has exactly the same lifetime as the struct type variable to which it belongs.

Array Elements

The elements of an array come into existence when an array instance is created and it ceases to exist when there are no references to that array instance:

int[] myArray = new int[]{1,2,3,4,5}; /* An array of int */

Value Parameters

A parameter declared without a ref or out modifier is a value parameter:

MethodA(10,10); /* MethodA calls with 10,10 */
...
void MethodA( int a, int b){} /* MethodA has two parameters a, b */

Reference Parameters

A parameter declared with a ref modifier is a reference parameter:

object myObject = new object();
ProcessObject(ref myObject);
...
static void ProcessObject(ref object aObject) {}

Output Parameters

A parameter declared with an out modifier is an output parameter. Listing 1-14 shows the use of the output parameter.

Listing 1-14. Example of Output Parameters

using System;

namespace Ch01
{
class Program
{
static void Main(string[] args)
{
int x;
WithOutInParameter(out x);
Console.WriteLine(x); /* 100 */
}

static void WithOutInParameter(out int a)
{ a = 100; }
}
}

This program will produce the output:

100

Local Variables

A local variable would be declared as:

typeName variableName = variable initializer or
var variableName = variable initializer

It may occur in a block, in a for statement, in a switch statement, or in a using statement. It can also occur in a foreach statement or a specific catch clause for a try statement:

void MethodA()
{
int a=10; /* Example of the local variable */
}

Listing 1-15 demonstrates the use of the local variable.

Listing 1-15. Example of the Local Variable Usage

using System;
using System.IO;
namespace Ch01
{
class Program
{
static void Main(string[] args)
{
AClass aClass = new AClass();
aClass.MethodA();
Console.ReadLine();
}
}

public class AClass
{
public void MethodA()
{
int a = 10;
switch (a)
{
case 7:
Console.WriteLine("...");
break;
case 10:
int b = 10;
Console.WriteLine(b);
break;
default: Console.WriteLine("Default"); break;
}
for (int i = 0; i < 5; ++i) ;
using (MemoryStream ms = new MemoryStream())
{
; /*Doing nothing*/
}
}
}
}

This program produces the output:

10

Local Variable in Compile Time

When the C# compiler compiles the program shown in Listing 1-15 into IL, it will add a local variable section for the Main method of the Program class and the same for the MethodA of the ACLass, as shown in Listing 1-16 and Listing 1-17.

Listing 1-16. Decompiled IL Code of the Main Method for Listing 1-15

.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
.maxstack 1

/* Local section of the MethodA which will hold all the local
* variable used in the MethodA*/
.locals init (
[0] class Ch01.AClass aClass)
/* code removed */
}

Listing 1-17. IL Code of the MethodA of the ACLass for Listing 1-15

.method public hidebysig instance void MethodA() cil managed
{
.maxstack 2

/* Local section of the MethodA which will hold all the local variable
* used in the MethodA*/
.locals init (
[0] int32 a,
[1] int32 b,
[2] int32 i,
[3] class [mscorlib]System.IO.MemoryStream ms,
[4] int32 CS$4$0000,
[5] bool CS$4$0001)
/* Code removed */
}

Listing 1-16 and Listing 1-17 show that for the .locals section of the Main method of the Program class, there is a variable for the instance of the AClass, and MethodA of the AClass has the six local variables:

· The variables a and b are used to hold the value of 10.

· The variable i is used in the for statement as a loop variable. The variable is declared in the for statement, but the C# is compiled by storing it in the local variable section of the MethodA. The same is true for the ms variable, which is used in the using statement.

· In the .locals section, there are two extra variables used in positions 4 and 5, such as CS$4$0000 and CS$4$0001. The CS$4$0000 variable is used to store the value for the case label used in the switch block. For example, for the case label value of 7 or 10, the C# complier will generate IL code such as ldc.i4.7 to load 7 in the CS$4$0000 variable or for the case label value 10 the IL instruction will be ldc.i4.s 10 to load the value into CS$4$0000. The variable CS$4$0001 is used to store the results of the condition i<5 (used in the statement in Listing 1-15).

Local Variable in Runtime

If you debug the executable of Listing 1-15 using the windbg.exe tool, the CLR will keep the value of the local variable in the LOCALS section of the MethodA stack, as shown in Figure 1-12.

images

Figure 1-12. Local variable in the method

Figure 1-12 shows that in the stack of the MethodA, the CLR stores 0x0000000a (10) in the 0x001af1d0 and b in the 0x001af1cc address. The address 0x001af1c8 is used for the i variable used in the for statement and 0x001af1b8 for the MemoryStream class. The 0x001af1c4 address for the case variable and 0x001af1c0address are used to store the bool value of the result of the condition (i<5) used in the for statement.

Parameters

Parameters are used in the .NET to pass data into the method as values or variable references. The parameters of a method get their actual values from the arguments that are specified when the method invokes:

public class AClass
{
public int MethodA(int a) /* a is the parameter for the MethodA*/
{ return a * 10; }
}

MethodA of the AClass has the parameter a, from which it gets its value, as shown in the code:

static void Main(string[] args)
{
AClass aClass = new AClass();
aClass.MethodA(10); /* 10 is the argument for the MethodA*/
}

In runtime of a method, the CLR stores all the values for the parameter used in that method, in addition to the extra value for the this keyword in the PARAMETERS section of the method Stack, as demonstrated in Figure 1-12.

Types of Parameter Passing

The sections that follow explain the different types of parameter passing:

· Passing arguments by value

· Ref modifier

· Out modifier

· Implications of passing by reference

· Params modifier

· Optional parameters

· Named arguments

Passing Arguments by Value

A value parameter is used for input parameter passing. A value parameter corresponds to a local variable that gets its initial value from the argument that is passed for the parameter. Modifications to a value parameter do not affect the argument that is passed for the parameter. Listing 1-18provides an example of parameter passing.

Listing 1-18. Passing Arguments by Value

using System;
namespace Ch01
{
class Program
{
static void Main(string[] args)
{
/* Initializes with 100 */
int x = 100;
Console.WriteLine("Before method call :\t{0}", x);

/* pass as value to the Increment method*/
Increment(x);
Console.WriteLine("After method call :\t{0}", x);
}

/* a is the parameter for the MethodA*/
static void Increment(int a)
{
++a;
Console.WriteLine("Incremented value :\t{0}",a);
}
}
}

This program produced the output:

Before method call : 100
Incremented value : 101
After method call : 100

The call of the Increment method will be passed with the value type; as a result, the increment of the value of parameter a in the Increment method does not update the original value of the X in the Main method.

Ref Modifier

A reference parameter is used for both input and output parameter passing, and during execution of the method, the reference parameter represents the same storage location as the argument variable. A reference parameter is declared with the ref modifier. The example in Listing 1-19 shows the use of the ref parameter.

Listing 1-19. Example of the Ref Parameter

using System;
namespace Ch01
{
class Program
{
static void Main(string[] args)
{
int x = 100; /* Needs to initialize x */
Console.WriteLine(x); /* 100 */
Increment(ref x); /* pass the location (0x052de8b4) of the x */
Console.WriteLine(x); /* 101 */
}
static void Increment(ref int a) /* a pointing to the same memory
* location as x (0x052de8b4)
* of Main method */
{ ++a; }
}
}

This program will produce the output:

100
101

Out Modifier

An output parameter is used for output parameter passing. An output parameter is similar to a reference parameter except that the initial value of the caller-provided argument is not necessary. An output parameter is declared with the out modifier. Listing 1-20 provides an example of the use of an out modifier.

Listing 1-20. Example of the Out Modifier

using System;
namespace Ch01
{
class Program
{
static void Main(string[] args)
{
int x; /* Does not need to initialize x */
SetInitialValue(out x);
Console.WriteLine(x); /* 1 */
}

static void SetInitialValue(out int a)
{ a = 1; }
}
}

This program will produce the output:

1

Implications of Passing by Reference

When an argument passes by reference to a method, the same storage location is used to access that variable. In Listing 1-20, x and a refer to the same location.

Params Modifier

A parameter array permits a variable number of arguments to be passed to a method. A parameter array is declared with the params modifier. Only the last parameter of a method can be a parameter array, and the type of a parameter array must be a single dimensional array type. Listing 1-21provides an example of the use of the params modifier.

Listing 1-21. Example of the Params Modifier

using System;
namespace Ch01
{
class Program
{
static void Main(string[] args)
{
string[] planets = { "Jupiter", "\n", "Pallas" };
Console.WriteLine("{0}", ConcatStrings(planets));
}

static string ConcatStrings(params string[] items)
{
string result = default(string);
foreach (string item in items)
{ result = string.Concat(result, item); }
return result;
}
}
}

This program will produce the output:

Jupiter
Pallas

Optional Parameters

A parameter can be optional if the default value for the parameter is specified in its declaration, as shown in Listing 1-22.

Listing 1-22. Example of the Optional Parameters

using System;
namespace Ch01
{
class Program
{
static void Main(string[] args)
{
Show(); /* Please specify message */
Show("Message set"); /* Message set */
}
static void Show( string message="Please specify message")
{
Console.WriteLine(message);
}
}
}

This program will produce the output:

Please specify message
Message set

Named Arguments

A named argument is used to identify the argument by name instead of its position. Listing 1-23 provides an example of the named argument.

Listing 1-23. Example of the Named Arguments

using System;
namespace Ch01
{
class Program
{
static void Main(string[] args)
{
Add(a: 10, b: 10); /* 20 */
Add(10, b: 10); /* 20 */
//Add(a: 10, 10); /* Compile time error, position */
}

static void Add(int a, int b)
{
Console.WriteLine(a + b);
}
}
}

This program will produce the output:

20
20

Kinds of Operators

There are three kinds of operators:

· Unary operators: The unary operators take one operand and use either prefix notation (such as –x) or postfix notation (such as x++).

· Binary operators: The binary operators take two operands and they all use infix notation (such as x - y).

· Ternary operator: Only one ternary operator, ?:, exists; it takes three operands and uses infix notation (condition? whenTrue: whenFalse).

Expressions are constructed from operands and operators. Table 1-13 summarizes the operators used in C#, listing the operator categories in order of precedence from highest to lowest. Operators in the same category have equal precedence.

images

images

Statements

The operations of a program are expressed using statements. C# supports several kinds of statements, a number of which are defined in terms of embedded statements. A block permits multiple statements to be written in contexts where a single statement is allowed.

A block consists of a list of statements separated using the delimiters (;):

{ list of statement }

Or,

{
statement ;
statement ;
statement ;
statement ;
}

Figure 1-13 demonstrates the possible different statements used in the C#.

images

Figure 1-13. Possible forms of the statements used in C#

The following sections will explore the labeled, embedded, and declaration statements in more detail.

Labeled Statements

A statement prefix with a label is denoted as a Label statement. A label statement can be declare as:

An identifier following by : with statement or statements.

It is used in a block rather than as an embedded statement. The goto statement can transfer control within blocks and out of blocks, but never into blocks. Let’s look at the following example:

public void MethodA()
{
int i = 0;
while (++i < int.MaxValue)
{
if (i == int.MaxValue / 2)
goto Display; /* Program control will transfer to the label
* Display when the condition meets. */
}
Display: Console.WriteLine(i);
}

The Display label can be written as:

Display:
{
Console.WriteLine("Labeled statement");
Console.WriteLine(i);
Console.WriteLine("End Labeled statement");
}

The Label statement is used in C# code to transfer the program control from one place to another. In IL code of the MethodA, the Label statement is translated using the instruction br, as demonstrated in Listing 1-24.

Listing 1-24. Decompiled IL Code for MethodA

.method public hidebysig instance void MethodA() cil managed
{
.maxstack 2
.locals init (
[0] int32 i,
[1] bool CS$4$0000)
L_0000: nop
L_0001: ldc.i4.0
L_0002: stloc.0
L_0003: br.s L_0018
L_0005: nop
L_0006: ldloc.0
L_0007: ldc.i4 0x3fffffff
L_000c: ceq
L_000e: ldc.i4.0
L_000f: ceq
L_0011: stloc.1
L_0012: ldloc.1
L_0013: brtrue.s L_0017

/* The program control will transfer to L_0028 to execute the statements
* define for the Display label in C#. It will skip the execution of the
* statements from L_0017 to L_0026 the CLR will execute the statement
* from L_0028 to L_0052.*/
L_0015: br.s L_0028

L_0017: nop
L_0018: ldloc.0
L_0019: ldc.i4.1
L_001a: add
L_001b: dup
L_001c: stloc.0
L_001d: ldc.i4 0x7fffffff
L_0022: clt
L_0024: stloc.1
L_0025: ldloc.1
L_0026: brtrue.s L_0005

/* Display labeled start from here and end at L_0045 */
L_0028: nop
L_0029: ldstr "Labeled statement"
L_002e: call void [mscorlib]System.Console::WriteLine(string)
L_0033: nop
L_0034: ldloc.0
L_0035: call void [mscorlib]System.Console::WriteLine(int32)
L_003a: nop
L_003b: ldstr "End Labeled statement"
L_0040: call void [mscorlib]System.Console::WriteLine(string)
L_0045: nop
L_0046: nop
L_0047: ldstr "Continue with the rest of the statements in the method"
L_004c: call void [mscorlib]System.Console::WriteLine(string)
L_0051: nop
L_0052: ret
}

Declaration Statements

A declaration statement is used to declare a local variable (which discussed earlier) or a constant. The following section further explains the constant variable declaration.

Constant Declarations

In a constant declaration, one or more constants can be declared. The following line of code shows that a constant variable book has been declared:

public const string book = "Expert C# 5.0";

Embedded Statement

The following sections will explore the different embedded statements, such as the empty statement, expression statement, selection statement, iteration statement, jump statement, try statement, lock statement, using statement, and yield statement.

Empty Statement

An empty statement does nothing but is used when there are no operations to perform. An empty statement can be declared as:

;
empty statement defined by ;

The following example is provided to explain the empty statement:

public void MethodA()
{
int i = 0;
while (++i < int.MaxValue)
; /* ; Does nothing in here except elapsed
* time to execute the looping until
* int.MaxValue reached*/
Console.WriteLine(i);
}

Expression Statements

An expression statement evaluates an expression. Expression statements will be one of the following:

· Invocation expression

· Object creation expression

· Assignment expression

· Post- or preincrement or post- or predecrement expression

The example in Listing 1-25 shows the usage of the different expressions.

Listing 1-25. Example of the Expression Statement

using System;
namespace Ch01
{
class Program
{
static void Main(string[] args)
{
int x, y; /* Declaration statement */
x = 10; /* Assignment expression */
y = 12; /* Assignment expression */
++x; /* Increment expression */
--y; /* Decrement expression */
Show(x, y); /* Method call expression which will
* show 22 as output*/
string message =
new string('.', 10); /* object instantiation expression */
Console.WriteLine(message); /* Method call expression which will
* show method */
}

static void Show(int a, int b)
{
Console.WriteLine(a + b);
}
}
}

This program will produce the output:

22
..........

Selection Statements

Selection statements are used in C# to select possible statements for execution based on a given condition. In C#, there are two kinds of selection statements: if and switch. The declaration of the if statement would be:

if ( boolean expression ) embedded statement

or

if ( boolean expression ) embedded statement else embedded statement

The declaration of the switch statement would be:

switch ( expression )
{
One or more switch block which consists of the switch label along with the statement or
statements.
}

The switch label would be:

case constant expression: statements
default: statements

The following example shows the usage of the if and switch statements:

public static void MethodA(int a)
{
if (a < 10)
{
switch (a)
{
case 1:
case 2:
case 3:
case 4:
/* Following statement will execute when a is in range
* of {1,2,3,4} */
Console.WriteLine(a);
break;

case 5:
/* Following statement will execute when a is 5 */
Console.WriteLine(a);
break;

default:
/* otherwise */
Console.WriteLine("Input < 10");
break;
}
}
else
{
Console.WriteLine("Input > 10");
}
}

MethodA will produce the following output for the value set {1, 4, 5, 7} when used in a program:

1
4
5
Input < 10

Iteration Statements

To execute repeated statements in C#, the while, do, for, and foreach statements would be used. The declaration of the while statement would be:

while ( boolean expression ) embedded statement

The declaration of the do statement would be:

do embedded statement while ( boolean expression ) ;

The declaration of the for statement would be:

for (
local variable declaration or statement expression;
boolean expression;
statement expression or statement expression list along with comma (,)
separated statement expression
)
embedded statement

The declaration of the foreach statement would be:

foreach (
local variable type follows by an identifier and this follows
in
along with an expression
)
embedded statement

The following is an example of the use of these statements:

public static void MethodA(int a) {
do
{
/* Iterate through the Enumerator and extract each of the item from
* the data source*/
foreach (char ch in "Expert C# 5.0" + Environment.NewLine)
Console.Write(ch);

/* loop through until does not meet the condition */
for (int i = 0; i <= 2; ++i)
++a;
} while (a <= 10); /* loop through until does not meet the condition */
}

MethodA will produce the following output for the value 1 when used in a program:

Expert C# 5.0 Expert C# 5.0
Expert C# 5.0
Expert C# 5.0

Jump Statements

To transfer the control of the program execution in C#, one of the jump statements, such as break, continue, goto, return, and throw, can be used. The declaration of the while statement would be:

break ;

The declaration of the continue statement would be:

continue ;

The declaration of the goto statement would be:

goto identifier ;

The declaration of the return statement would be:

return expression ;

The declaration of the throw statement would be:

throw expression ;

The following example explains the use of statements:

public static void MethodA(int a) {
do
{
foreach (char ch in "Expert C# 5.0\t" + Environment.NewLine)
{
if (Environment.NewLine.Contains(ch.ToString()))
break;
Console.Write(ch);
}
} while ((a = MethodB(a)) <= 10);
}

public static int MethodB(int a)
{
if (a == 100)
throw new Exception("Error: a>10");
return ++a;
}

MethodA and MethodB will produce the following output for the value 1 when used in a program:

Expert C# 5.0 Expert C# 5.0 Expert C# 5.0 Expert C# 5.0 Expert C# 5.0
Expert C# 5.0 Expert C# 5.0 Expert C# 5.0 Expert C# 5.0 Expert C# 5.0

Try Statement

The try statement provides a mechanism for catching exceptions that occur during execution of a block. Furthermore, the try statement provides the ability to specify a block of code that is always executed when control leaves the try statement:

public static int MethodB(int a)
{
try
{
return Int16.MaxValue / a;
}
catch (DivideByZeroException dbze)
{
Console.WriteLine(dbze.Message);
}
finally
{
Console.WriteLine("Execute always");
}
return -1;
}

MethodB will produce the following output for the value 0 when used in a program:

Attempted to divide by zero. Execute always
-1

Lock Statement

The lock statement obtains the mutual exclusion lock for a given object, executes a statement, and then releases the lock. The lock statement can be declared as in the following example:

lock ( expression ) embedded-statement

A lock statement of the form of

lock(x) {/* some code */ }

is compiled by the C# compiler, as shown in the following pseudo code:

System.Threading.Monitor.Enter(x);
try { /* some code */ }
finally { System.Threading.Monitor.Exit(x); }

Listing 1-26 shows an example of the lock statement.

Listing 1-26. Example of Lock Statement Using Value Type

using System;
namespace Ch01
{
class Program
{
static void Main(string[] args)
{
int a = 0;
lock (a)
{
Console.WriteLine(a);
}
}
}
}

When you compile Listing 1-26, the C# compiler will generate the following compile-time error:

'int' is not a reference type as required by the lock statement

The reason for the compile-time error is because the lock statement can be used for the reference type, not for the value type, as demonstrated in Listing 1-27.

Listing 1-27. Example of the Lock Statement Using the Reference Types

using System;
namespace Ch01
{
class Program
{

static void Main(string[] args)
{
AClass anObject = new AClass();
lock (anObject)
{
Console.WriteLine(anObject.ToString());
}
}
class AClass { }
}
}

This program produces the output:

Ch01.Program+AClass

Let’s look at the IL code of Listing 1-27 to see how the C# compiler compiles the lock statement. Listing 1-28 shows how the C# compiler handles the lock statement behind the scenes.

Listing 1-28. IL Equivalent of Listing 1-27

.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 54 (0x36)
.maxstack 2
.locals init ([0] class Ch01.Program/AClass anObject,
[1] bool '<>s__LockTaken0',
[2] class Ch01.Program/AClass CS$2$0000,
[3] bool CS$4$0001)
IL_0000: nop
IL_0001: newobj instance void Ch01.Program/AClass::.ctor()
IL_0006: stloc.0
IL_0007: ldc.i4.0
IL_0008: stloc.1

/* try..finally block added to the code */
.try
{
IL_0009: ldloc.0
IL_000a: dup
IL_000b: stloc.2
IL_000c: ldloca.s '<>s__LockTaken0'

/* Instance of the AClass is now Enter into the Threading Monitor and from
* IL_0013 to IL_0021 the CLR will work with it whatever it requires to.*/
IL_000e: call void [mscorlib]System.Threading.Monitor::Enter(object,
bool&)
IL_0013: nop
IL_0014: nop
IL_0015: ldloc.0
IL_0016: callvirt instance string [mscorlib]System.Object::ToString()
IL_001b: call void [mscorlib]System.Console::WriteLine(string)
IL_0020: nop
IL_0021: nop

/* leave.s instruction will execute the closest finally block which
* will release the instance of the AClass and '<>s__LockTaken0'
* will be released.*/
IL_0022: leave.s IL_0034
} // end .try
finally
{
IL_0024: ldloc.1
IL_0025: ldc.i4.0
IL_0026: ceq
IL_0028: stloc.3
IL_0029: ldloc.3
IL_002a: brtrue.s IL_0033
IL_002c: ldloc.2

/* Release the lock of the anObject instance.*/
IL_002d: call void [mscorlib]System.Threading.Monitor::Exit(object)
IL_0032: nop
IL_0033: endfinally
} // end handler
IL_0034: nop
IL_0035: ret
}

Using Statement

The using statement obtains one or more resources, executes a statement, and then disposes of the resource. The declaration statement of the using statement is:

using ( resource-acquisition ) embedded-statement
resource-acquisition:
local-variable-declaration
expression

Listing 1-29 shows the usage of the using statement.

Listing 1-29. Example of the Using Statement

using System;
using System.IO;
using System.Text;

namespace Ch01
{
class Program
{
static void Main(string[] args)
{
MethodB();
}

public static void MethodB()
{
using (MemoryStream ms =
new MemoryStream(Encoding.ASCII.GetBytes("Expert C# 5.0")))
{
int i = 0;
do
{
int current = ms.ReadByte();
Console.Write("{0}\t{1}\n", current, (char)current);
} while (++i < ms.Length);
}
}
}
}

This program will produce the output:

69 E
120 x
112 p
101 e
114 r
116 t
32
67 C
35 #
32
53 5
46 .
48 0

The using statement is discussed in detail in Chapter 13.

Yield Statement

The yield statement is used in an iterator block to yield a value to the enumerator object or enumerable object. The yield statement can be used in one of the following forms:

yield return <expression>;
yield break;

There are a few restrictions on use of the yield statement:

· It cannot be used outside the method body.

· It cannot be used in the anonymous function.

· It cannot be used in the finally block of the try block.

· It cannot be used in the try statement that contains any catch statement.

If you do any of the above, the C# compiler will complain. Listing 1-30 shows the usage of the yield statement.

Listing 1-30. Example of Yield Statement

using System;
using System.Collections;

namespace Ch01
{
class Program
{
static void Main()
{
foreach (int i in GeneratePower(2, 4))
{
Console.Write("{0} ", i);
}
}

public static IEnumerable GeneratePower(int initialValue, int range)
{
int result = 1;
for (int counter = 0; counter < range; ++counter)
{
result = result * initialValue;
yield return result;
}
}
}
}

This program will produce the output:

2 4 8 16

The yield statement and it iterator are discussed in Chapter 9.

Namespaces

In C#, a namespace is used to organize a program. A namespace declaration starts with the keyword namespace and it is followed by the name and body of the namespace. An optional ; (semicolon) can be used to declare a namespace. Listing 1-31 presents an example of the use of the namespace.

Listing 1-31. Example of the Namespace

namespace Ch01
{
class A { }
class B { }
}

The declaration of the namespace starts with a qualified identifier, which can be a single identifier or multiple identifiers separated with dot (.) tokens. As a result, the following two namespace declarations, as declared in Listing 1-32 and Listing 1-33, will be treated the same by the C# compiler.

Listing 1-32. Namespace Declaration with Multiple Identifier Separator (.)

namespace Ch01Level3.Ch01Level2.Ch01Level1
{
class ClassA { }
}

Listing 1-33. Namespace Declaration with Multiple Identifier Separator (.)

namespace Ch01Level3
{
namespace Ch01Level2
{
namespace Ch01Level1
{
class ClassA { }
}
}
}

The namespace declared in Listing 1-32 and Listing 1-33 is compiled as shown in Listing 1-34.

Listing 1-34. Namespace with Multiple Identifier

namespace Ch01Level3.Ch01Level2.Ch01Level1
{
internal class ClassA
{
/* Methods */
public ClassA();
}
}

When two namespaces are declared with the same fully qualified name, the C# compiler combines those declarations of the namespace inside one qualified name, as shown in Listing 1-35.

Listing 1-35. Multiple Namespace with Same Fully Qualified Name

namespace Ch01
{
class ClassA { }
}

namespace Ch01
{
class ClassB { }
}

Listing 1-35 is compiled as shown in Listing 1-36 to combine same namespace declarations.

Listing 1-36. Combined Namespace

namespace Ch01
{
internal class ClassA {}
internal class ClassB {}
public class Person {}
internal class Program {}
}

The using directive is used to import a namespace, as shown in Listing 1-37.

Listing 1-37. Usage of the Using Directive

namespace Ch01.Using
{
using Ch01; /* using statement imports the namespace
* defined in the Listing 1-36 */
using One=Ch01; /* using alias directives One refers to
* the Ch01 */
class ClassC
{
private ClassB classB;
private One.ClassA classA;
}
}

Class

Class is the most fundamental of all of the types in C#. A class is a data structure that combines state (properties) and actions (methods) in a single block. A class provides a definition for dynamically created instances of the class, also known as objects. A class will support:

· Inheritance

· Polymorphism

· A mechanism in which derived classes can extend and specialize base classes

Figure 1-14 shows the possible ways to declare a class.

images

Figure 1-14. Possible forms of the class declaration

An example of the class declaration is shown in Listing 1-38.

Listing 1-38. Example of the Class Declaration

using System;
namespace Ch01
{
class Program
{
static void Main(string[] args)
{
Person person = new Person()
{
Name = "Person A",
Address = "Address of Person A"
};
Console.WriteLine(person.ToString());
}
}

public class Person
{
public override string ToString()
{
return string.Format("Name: {0}\nAddress:{1}", Name, Address);
}

public string Name { get; set; }
public string Address { get; set; }
}
public class Address {}; /* ; is optional and it used in here
* to show the usage of it.*/
}

This program will produce the output:

Name: Person A Address: Address of Person A

In Listing 1-38, a class Person is declared with public accessibility using the accessibility modifier as public. It has two properties—Name, Address (declared using the automatic property declaration)—and this class overrides the ToString method of the base class (for all the classes in C#) or objectclass.

Object

The type object is the root of the entire type hierarchy in C#, so all types are compatible with it, for example:

object person = new Person();
Person anotherPerson = (Person) person;

The class System.Object contains the following methods inherited by all classes and structs:

· Equals

· ToString

· GetHashCode

Instances of classes are created using the new operator, which:

· Allocates memory for a new instance

· Invokes a constructor to initialize the instance

· Returns a reference to the instance

The following statements create two Point objects and store references to those objects in two variables—p1 and p2:

Point p1 = new Point(0,0);
Point p2 = new Point(20,30);

The memory occupied by an object is automatically reclaimed when the object is no longer in use. It is neither necessary nor possible to explicitly reallocate objects in C#.

Class Members

The members of a class are either static members or instance members. Static members belong to classes, and instance members belong to objects (instances of classes). Table 1-14 provides an overview of the different kinds of members a class can contain.

images

Accessibility

A class can have one of the five forms of accessibility:

· Public: There is no limit of access.

· Protected: It is accessible within the containing type.

· Protected internal: It defines the access is limited to the containing class or types derived from the containing class.

· Internal: It defines the access is limited to the program.

· Private: It defines the access is limited to the program or types derived from the continuing class.

There are some pros and cons of these modifiers, such as, you cannot use the modifiers private, protected, or protected internal when a class is defined in a namespace. Use of these modifiers by the C# compiler generates compile-time error:

namespace Ch01
{
private class ClassA {}
protected class ClassB {}
protected internal class ClassC {}
}

The C# compiler complains when compiling this code and shows the following error message:

Elements defined in a namespace cannot be explicitly declared as private, protected, or protected
internal

On the other hand, use of the private, protected, or protected internal is valid in nested class, as shown in the following code:

namespace Ch01
{
class Program
{
static void Main(string[] args) {}
}
public class ClassA {}
internal class ClassB {}

/* Nested classes allowed protected, private or protected internal
* modifiers for class declaration */
public class ClassC
{
protected class ClassD {}
private class ClassE {}
protected internal class ClassF {}
}
}

The modifier internal is the default accessibility for any class when the accessibility has not been specified explicitly:

class Planets { }; /* a class declaration without
* specifying accessibility */

This will be compiled as follows:

internal class Planets /* The C# compiler sets internal as
* the accessibility */
{
public Planets(){} /* default constructor provided by
* the C# compiler */
}

The derived class cannot have greater accessibility than the base class, as shown in the following code:

namespace Ch01
{
internal class ClassA {}
public class ClassB:ClassA {}
}

The C# compiler produces the following compile-time error while it compiles this code:

Inconsistent accessibility: base class 'Ch01.ClassA' is less accessible than class 'Ch01.ClassB'

In the access modifier usage, union of modifiers is not allowed except for the protected internal. Listing 1-39 presents an example of this.

Listing 1-39. Example of Access Modifiers Usage

namespace Ch01
{
class Program
{
static void Main(string[] args) {}
protected internal void MethodA() {} /* Valid use of access modifiers
* combination */
public internal void MethodA() {} /* Invalid use of access
* modifiers combination */
private internal void MethodA() {} /* Invalid use of access
* modifiers combination */
}
}

Listing 1-39 produced the following exception due to the multiple protection modifiers:

Error 11 More than one protection modifier J:\Book\ExpertC#2012\SourceCode\
BookExamples\Ch01\Program.cs 7 16 Ch01
Error 12 More than one protection modifier J:\Book\ExpertC#2012\SourceCode\
BookExamples\Ch01\Program.cs 8 17 Ch01

Types of Classes

There are three types of classes: abstract classes, sealed classes, and static classes. The following sections discuss each of these in detail.

Abstract classes

The abstract class is intended to be used only as a base class, and it can only be used as the base class of another class. You cannot create instances of an abstract class, and an abstract class is declared using the abstract modifier. An abstract class can contain abstract members or regular, nonabstract members. The members of an abstract class can be any combination of abstract members and normal members with implementations. An abstract class can itself be derived from another abstract class. For example, the code in Listing 1-40 shows a class derived from an abstract class. Any class derived from an abstract class must implement all the abstract members of the class by using the override keyword, unless the derived class is itself abstract.

Listing 1-40. Example of Abstract Class

using System;
namespace Ch01
{
class Program
{
static void Main(string[] args)
{
StandardCalculator sc = new StandardCalculator();
Console.WriteLine(sc.Add(10, 10)); /* 20 */
Console.WriteLine(sc.Sub(10, 10)); /* 0 */
}
}

public abstract class Calculator
{
public abstract int Add(int a, int b);
public int Sub(int a, int b) { return b - a; }
}

public class StandardCalculator : Calculator
{
public override int Add(int a, int b) { return a + b; }
}
}

This program will produce the output:

20
0

Sealed Classes

The sealed modifier is used to prevent derivation from a class. Listing 1-41 presents an example of the sealed class.

Listing 1-41. Example of Sealed Class

using System;
namespace Ch01
{
class Program
{
static void Main(string[] args)
{
Person person = new Person
{
Age = 30
};
}
}

public sealed class Person
{
public int Age { get; set; }
}
}

A sealed class cannot be used as the base class of another class, otherwise a compile-time error occurs, for example, if the Person class is used as a base class, as in the code that follows:

public sealed class Person
{
public int Age { get; set; }
}

public class Alien : Person { }

The C# compiler will throw the following compile-time error:

'Ch01.Alien': cannot derive from sealed type 'Ch01.Person'

A sealed class cannot also be an abstract class. The sealed class gives certain runtime optimizations, for example, the C# complier could possibly transform the virtual function member invocations on sealed class instances into nonvirtual invocations. Most often, sealing a class makes the best sense when you are designing a utility class. For example, the System namespace defines numerous sealed classes.

Static Classes

The static modifier is used to mark the class declared as a static class. A static class has following characteristics:

· It cannot be used to instantiate.

· It can contain only the static members, otherwise it produces a compile-time error, for example: “cannot declare instance members in a static class".

· The extension method can be declared only in the static class.

· A static class may not include a sealed or abstract modifier.

· The access modifiers protected or protected internal cannot be used to define members in a static class, otherwise it produces a compile-time error, for example, for protected: "static classes cannot contain protected members".

· An instance constructor cannot be declared in the static class, otherwise it produces a compile-time error, for example: "Static classes cannot have instance constructors".

Listing 1-42 shows an example of the static class.

Listing 1-42. Example of Static Class

using System;
namespace Ch01
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("{0}", Calculator.Add(10, 10));
}
}

public static class Calculator /* A static class declaration */
{
/* A static method declaration */
public static int Add(int a, int b) { return a + b; }
}
}

This program will produce the output:

20

A static class does not contain any default constructor, for example, the IL version of the Calculator class, as demonstrated in the following code:

.class public abstract auto ansi sealed beforefieldinit Calculator
extends [mscorlib]System.Object
{
.method public hidebysig static int32 Add(int32 a, int32 b) cil managed{}
}

The IL code shows that the static class does not contain any default constructor unless you define the static constructor.

Constructor

C# supports both instance and static constructors. An instance constructor is a member that implements the actions required to initialize an instance of a class. A static constructor is a member that implements the actions required to initialize a class itself when it is first loaded. The following code shows an example of the instance constructor of a class:

public class Person
{
private string name;
public Person() /* Constructor for the Person class */
{
name=string.Empty;
}
}

Default Constructors

If a class contains no instance constructor declarations, a default instance constructor is provided automatically by the C# compiler. That default constructor simply invokes the parameterless constructor of the direct base class. If the direct base class does not have an accessible parameterless instance constructor, a compile-time error occurs. If the class is abstract, then the declared accessibility for the default constructor is protected.

Listing 1-43. Example of Default Constructors

using System;
namespace Ch01
{
class Program
{
static void Main(string[] args)
{
Person person = new Person();
}
}

public class Person
{
/* Empty class, there hasn't been declared any explicit constructor,
* property or method. After compiling C# compiler will add a
* default constructor*/
}
}

When compiling the program in Listing 1-43, the C# compiler adds the default constructor to the Person class as shown in the code:

.class public auto ansi beforefieldinit Person extends [mscorlib]System.Object
{
/* Default constructor .ctor generated by the C# compiler for the
* Person class. */
.method public hidebysig specialname rtspecialname instance
void .ctor() cil managed {}
}

images Note: Chapter 15 discusses the .ctor and .cctor constructors.

Private Constructors

When a class C declares only private instance constructors, it is not possible for classes outside of C to be derived from C or to directly create instances of C, as shown in the code that follows:

public class Person
{
private string name;
private Person() /* private constructor */
{
name = string.Empty;
}
}

The Person class will be inaccessible while trying to instantiate an instance of the Person class, and the C# compiler will show following message:

Ch01.Person.Person()' is inaccessible due to its protection level

If a class contains only static members and you do not want it to be instantiated, you can prevent instantiation of that class by adding a private constructor. In addition, if you have a class that does not have an instance field or instance method, a private constructor can be used to prevent instantiation of that class. If you have a class that contains only constants, you can use a private constructor to prevent instantiation, because accessing constants from the class does not require you to have an object of the class.

Optional Instance Constructor Parameters

The this(...) form of constructor initializer is commonly used in conjunction with overloading to implement optional instance constructor parameters.

Static Constructor

A static constructor is a member that implements the actions required to initialize a closed class type. Listing 1-44 presents an example of the static constructor.

Listing 1-44. Possible Forms of the Static Constructors

using System;

namespace Ch01
{
class Program
{
public static int Y = StaticClass.X + 1; /* StaticClass.X= 1 */
static Program() { }
static void Main()
{
Console.WriteLine("X = {0}, Y = {1}", StaticClass.X, Program.Y);
}
}

class StaticClass
{
public static int X; /*0*/
static StaticClass()
{
X = Program.Y + 1; /* Program.Y = 0 */
}
}
}

This program will produce the output:

X = 1, Y = 2

Field

A field is a variable that is associated with a class or with an instance of a class. The initial value of a field, whether it is a static field or an instance field, is the default value of the field’s type. Figure 1-15 demonstrates the declaration of the field.

images

Figure 1-15. Possible forms of the field declaration

The following code indicates two fields—Name and FirstTwoDigitOfDob—have been declared:

public class Person
{
public string Name = "Mohammad Rahman"; /* A field of type string */
public int FirstTwoDigitOfDob = 19; /* A field of type int */
public int a = 0, b = 1, c = 2; /* Multiple variable declarator */
}

Figure 1-15 shows that when you declare a field, you can use the new modifier to suppress the warning when the same member name was used in the derived class, as demonstrated in the code:

public class AClass
{
public string Name;
}

public class BClass : AClass
{
public string Name; /* Same field name used in the derived class */
}

This code produced the following compile-time warning:

Warning 150 'Ch01.BClass.Name' hides inherited member 'Ch01.AClass.Name'. Use the new
keyword if hiding was intended.

Usage of the new modifier in the Name field declaration in the BClass will eliminate this warning. As a modifier, you can also use the volatile keyword, which indicates that the field declared with the volatile keyword might be modified by concurrent threads execution.

There are four kinds of fields in C#: static field, instance field, readonly field, and volatile field. Each of these is discussed in the sections that follow.

Static Field

A field declared with the static modifier defines a static field. A static field identifies exactly one storage location. No matter how many instances of a class are instantiated, there is only ever one copy of a static field, as shown in the following code:

public static int FirstTwoDigitOfDob = 19; /* A static field of type int */

Instance Field

A field declared without the static modifier defines an instance field, as shown in the following code:

public int FirstTwoDigitOfDob = 19; /* An instance field of type int */

The instance variable comes into existence when an instance of that class is instantiated, and every instance of a class contains a separate copy of all the instance fields of that class. The initial value for the instance fields is the default value of the variable’s type.

When you initialize an instance field, you cannot reference the instance field being created, as shown in the following code:

public class AClass
{
public int a = 0;
public int b = a + 1; /* The C# compiler complains about this line
* of statement */
}

In the AClass, the instance field b tries to access the value of a, which was just created, but the C# compiler raised the following compile-time error:

A field initializer cannot reference the non-static field, method, or property 'Ch01.AClass.a'

Readonly Field

When a field declaration includes a readonly modifier, the fields introduced by the declaration are readonly, as shown in the following code:

/* An readonly field of type int */
public readonly int FirstTwoDigitOfDob = 19;

Volatile Field

When a field declaration includes a volatile modifier, the fields introduced by that declaration are volatile fields, as shown in the following code:

/* An volatile field of type int */
public static volatile int FirstTwoDigitOfDob = 19;

Methods

A method is a member that implements the operations that can be performed by an object or class. A method has a (possibly empty) list of parameters, which represent values or variable references passed to the method, and a return type, which specifies the type of the value computed and returned by the method. Figure 1-16 demonstrates the possible forms of the method declaration.

images

Figure 1-16. Possible forms of the method declaration

Listing 1-45 presents an example of the method declaration in C#.

Listing 1-45. Example of the Method Declaration

using System;
namespace Ch01
{
class Program
{
/* A static method */
static void Main(string[] args)
{
AClass anInstanceOfAClass = new AClass();
anInstanceOfAClass.Display();
}
}

public class AClass
{
/* An instance method */
public void Display()
{
Console.WriteLine("Hello world! from the Main method");
/* Hello world! from the Main method */
}
}
}

This program will produce the output:

Hello world! from the Main method

When you derive a class called BClass from AClass and implement a method with the same name as Display, as shown in the code:

public class BClass:AClass
{
/* An instance method */
public void Display()
{
Console.WriteLine("Hello world! from the Main method");
/* Hello world! from the Main method */
}
}

the C# compiler will raise a warning, as follows:

Warning 150 'Ch01.BClass.Display()' hides inherited member 'Ch01.AClass.Display()'. Use the
new keyword if hiding was intended.

To eliminate that warning, we need to add the new modifier in the method header, as shown in Figure 1-16. The Display method of the BClass requires the new modifier, as shown in the following code:

public new void Display()
{
Console.WriteLine("Hello world! from the Main method");
/* Hello world! from the Main method */
}

Types of Methods

There are several types of methods: static methods, instance methods, virtual methods, override methods, sealed methods, abstract methods, external methods, partial methods, and extension methods. These are discussed in the sections that follow.

Static Method

A static method cannot be used on a specific instance and can only directly access static members. Listing 1-46 presents an example of the static method.

Listing 1-46. Example of the Static Method

using System;

namespace Ch01
{
class Program
{
static void Main()
{
AClass.Method1(); /* Call Method1 but Method2 is not
* accessible outside of the AClass*/
Console.ReadLine();

}
}
public static class AClass
{
public static void Method1()
{
Console.WriteLine("Method 1");
Method2();
}
private static void Method2()
{
Console.WriteLine("Method 2");
}
}
}

This program will produce the output:

Method 1
Method 2

In a static class, it is an error to refer to the this keyword in a static method, so the compiler will generate a compile-time error:

"Keyword 'this' is not valid in a static property, static method, or static field initializer"

Instance Method

The instance method operates on a specific instance and can access both static and instance members. The this keyword can be used in the instance on which an instance method was invoked. Listing 1-47 presents an example of the instance method.

Listing 1-47. Example of the Instance Method

using System;
namespace Ch01
{
class Program
{
static void Main()
{
AClass anObjectOfAClass = new AClass();
anObjectOfAClass.Method1();
Console.ReadLine();
}
}
public class AClass
{
public void Method1()
{
Console.WriteLine("Method 1");
this.Method2(); /* this keyword used to invoke Method2 */
}
private void Method2()
{
Console.WriteLine("Method 2");
Method3(); /* this keyword can not be used to
* static Method3 */
}
public static void Method3()
{
Console.WriteLine("Method 2");
}
}
}

This program will produce the output:

Method 1
Method 2
Method 2

Virtual Method

The actual virtual method implementation is determined based on the runtime type of the instance for which the invocation takes place, whereas the compile-time type is used for the nonvirtual method. A derived class D can override the virtual method defined in the base class B (D:B). The override modifier overrides an inherited virtual method. A new implementation can provide for the virtual method defined in the base class. Listing 1-48 presents an example of the virtual method.

Listing 1-48. Example of the Virtual Method

using System;
namespace Ch01
{
class Program
{
static void Main()
{
D anObjectOfDClass = new D();
anObjectOfDClass.Method1();
Console.ReadLine();
}
}

public class B
{
public virtual void Method1()
{
Console.WriteLine(ToString());
}
}

public class D : B
{
public override void Method1() /* virtual method overriden */
{
Console.WriteLine(ToString());
}
}
}

This program will produce the output:

Ch01.D

Abstract Method

An abstract method is declared with the abstract modifier and is permitted only in a class that is also declared abstract. An abstract method is a virtual method with no implementation. An example would be if Method2 is defined as abstract in the nonabstract class AClass, as shown in the following code:

public abstract class BaseClass
{
public abstract void Method1();
}

public class AClass : BaseClass
{
public override void Method1()
{
Console.WriteLine(ToString());
}

public abstract void Method2(); /* The C# compiler complain about
* the Method2 */
}

The C# compiler raised a compile-time error:

'Ch01.AClass.Method2()' is abstract but it is contained in non-abstract class 'Ch01.AClass'

An abstract method must be overridden in every nonabstract-derived class. Listing 1-49 shows an example of the abstract method.

Listing 1-49. Example of the Abstract Method

using System;
namespace Ch01
{
class Program
{
static void Main()
{
AClass anObjectOfAClass = new AClass();
anObjectOfAClass.Method1();
Console.ReadLine();

}
}
public class AClass : BaseClass
{
public override void Method1()
{
Console.WriteLine(ToString());
}
}

public abstract class BaseClass
{
public abstract void Method1();
}
}

This program will produce the output:

Ch01.AClass

Sealed Method

When an instance method declaration includes a sealed modifier, that method is said to be a sealed method. If an instance method declaration includes the sealed modifier, it must also include the override modifier (the Method2 method from the AClass), as shown in Listing 1-50.

Listing 1-50. Example of the Sealed Method

using System;
namespace Ch01
{
class Program
{
static void Main()
{
AClass anObjectOfAClass = new AClass();
anObjectOfAClass.Method1();
anObjectOfAClass.Method2();

BClass anObjectOfBClass = new BClass();
anObjectOfBClass.Method1();
Console.ReadLine();
}
}

public class BaseClass
{
public virtual void Method1() { Console.WriteLine(ToString()); }
public virtual void Method2() { Console.WriteLine(ToString()); }
}

public class AClass : BaseClass
{
public override void Method1() { Console.WriteLine(ToString()); }
public sealed override void Method2()
{ Console.WriteLine(ToString()); }
}

public class BClass : AClass
{
public override void Method1() { Console.WriteLine("Overriden"); }
}
}

This program will produce the output:

Ch01.AClass
Ch01.AClass
Overriden

A sealed method defined in the base class is not overridden in the derived class; for example, further overriding of Method2 of the AClass from the BClass, as shown in the code that follows, will throw a compile-time error:

public class BClass : AClass
{
public override void Method1()
{
Console.WriteLine("Overriden");
}
public override void Method2()
{
Console.WriteLine("Overriden");
}
}

The compile-time error would be:

'Ch01.BClass.Method2()': cannot override inherited member 'Ch01.AClass.Method2()' because it is
sealed

External Method

When a method declaration includes an extern modifier, that method is said to be an external method. To use a method to define externally typical language other than C#, the extern modifier is used. For example, if you want to use a Win32 method Beep in a C# application, you need to use theextern modifier. The extern modifier is used in DllImport as an attribute. The DllImport needs to mention in which Dynamic Link Libraries (DLL) it implemented the relevant method, for example, the Beep method defined in the User32.dll. In addition, a static modifier must be included when accessing the external method via extern. Listing 1-51 shows an example of the external method.

Listing 1-51. Example of the External Method

using System;
using System.Runtime.InteropServices;
namespace Ch01
{
class Program
{
[DllImport("User32.dll")]
static extern Boolean MessageBeep(UInt32 beepType);

static void Main()
{
MessageBeep((UInt32)BeepTypes.MB_ICONEXCLAMATION);
}
enum BeepTypes
{
MB_ICONASTERISK = 0x00000040,
MB_ICONEXCLAMATION = 0x00000030
}
}
}

Override Method

When an instance method declaration includes an override modifier, the method is said to be an override method. An override method overrides an inherited virtual method with the same signature. The overridden base method is a virtual, abstract, or override method. A sealed base method cannot be declare as overridden. Listing 1-52 shows an example of the override method.

Listing 1-52. Example of the Override Method

using System;
namespace Ch01
{
class Program
{
static void Main()
{
AClass anObjectOfAClass = new AClass();
anObjectOfAClass.Method1();
anObjectOfAClass.Method2();
Console.ReadLine();
}
}

public abstract class BaseClass { public abstract void Method1();}

public class BaseClass2 : BaseClass
{
public override void Method1()
{
Console.WriteLine(
"Method1 of the BaseClass overridden in the BaseClass2");
}

public virtual void Method2()
{ Console.WriteLine("Method2 define as virtual in the BaseClass2"); }

}
public class AClass : BaseClass2
{
public override void Method1()
{ Console.WriteLine("Method1 of the AClass overridden"); }
public override void Method2()
{ Console.WriteLine("Method2 of the AClass overridden"); }
}
}

This program will produce the output:

Method1 of the AClass overridden
Method2 of the AClass overridden

If you do not use the overridden Method2 in the AClass, as shown in the following code:

public class AClass : BaseClass2
{
public override void Method1()
{
Console.WriteLine("Method1 of the AClass overridden");
}
/* Method2 removed from the AClass */
}

and instead use the following code:

AClass anObjectOfAClass = new AClass();
anObjectOfAClass.Method1();
anObjectOfAClass.Method2();
Console.ReadLine();

it will produce the output:

Method1 of the AClass overridden
Method2 define as virtual in the BaseClass2

Partial Method

A partial method has its signature defined in one part of a partial type, and its implementation is defined in another part of the type. The partial method enables class designers to provide method hooks, similar to event handlers, that developers can decide whether or not to implement. If the developer does not supply an implementation, the compiler removes the signature at compile time. The following conditions apply to partial methods:

· Signatures in both parts of the partial type must match.

· The method must return void.

· No access modifiers or attributes are allowed. Partial methods are implicitly private.

Listing 1-53 provides an example that shows a partial method defined in two parts of a partial class.

Listing 1-53. Example of the Partial Method

using System;
namespace Ch01
{
class Program
{
static void Main()
{
A anObject = new A();
}
}

public partial class A
{
public A() { MethodOfA("Partial method"); }
partial void MethodOfA(string s);
}

/* This part can be in a separate file. */
public partial class A
{
partial void MethodOfA(String s) { Console.WriteLine("{0}", s); }
}
}

This program will produce the output:

Partial method

Extension and Anonymous Methods

The extension and anonymous methods will be discussed in detail in Chapter 4.

Properties

Properties are a natural extension of fields. Both are named members with associated types, and the syntax for accessing fields and properties is the same. However, unlike fields, properties do not denote storage locations. Instead, properties have accessors that specify the statements to be executed when their values are read or written. Figure 1-17 demonstrates the possible forms of the properties declaration.

images

Figure 1-17. Possible forms of the properties declaration

The following code is presented as an example:

public class Person
{
private string address;
public string Name /* Implicit property declaration */
{
get;
set;
}
public string Address
{
get { return address; } /* get accessor*/
set { address = value; } /* set accessor*/
}
}

Indexers

An indexer is a member that enables objects to be indexed in the same way as an array. An indexer is declared like a property except that the name of the member is this followed by a parameter list written between the delimiters [ and ]. Figure 1-18 demonstrates the possible forms of the index declaration.

images

Figure 1-18. Possible forms of the indexers declaration

Listing 1-54 presents an example of the use of the indexer.

Listing 1-54. Example of the Indexer

using System;
namespace Ch01
{
public delegate void EventHandler(string name);

class Program
{
static void Main(string[] args)
{
Planets planets = new Planets();
for (int i = 0; i <= 8; ++i)
Console.Write("{0}\t",planets[i]);
Console.ReadLine();
}
}

public class Planets
{
private string[] nameOfThePlanets =
{ "Sun", "Mercury", "Venus", "Earth", "Mars", "Jupiter",
"Saturn", "Uranus", "Neptune" };

public string this[int index]
{
get
{
return nameOfThePlanets[index];
}
set
{
nameOfThePlanets[index] = value;
}
}
}
}

This program will produce the output:

Sun Mercury Venus Earth Mars Jupiter Saturn Uranus Neptune

Automatically Implemented Properties

When a property is specified as an automatically implemented property, a hidden backing field is inserted by the C# compiler for the property, and the accessors are implemented to read from and write to that backing field. Listing 1-55 presents an example that shows the automatic implemented properties.

Listing 1-55. Example of the Automatic Implemented Properties

namespace Ch01
{
class Program
{
static void Main(string[] args)
{
Book aBook = new Book
{
Name = "Expert C# 5.0: with the .NET 4.5 Framework"
};
}
}
public class Book
{
public Book()
{ Name = default(string); }

public string Name

{ get; set; }
}
}

When the C# compiler compiles the code in Listing 1-55, it will add the extra field <Name>k_BackingField for the Name property. This will be explored in depth in Chapter 5.

Struct

Structs are data structures that can contain data members and function members, but unlike classes, they are value types and do not require Heap allocation. A variable of a struct type directly stores the data of the struct. Figure 1-19 demonstrates the possible struct declarations in C#.

images

Figure 1-19. Possible forms of the struct declaration

Listing 1-56 presents an example of the struct.

Listing 1-56. Example of the Struct

public struct Point
{
public const int ZeroPoint = 0; /* Constant declaration */
public int X; /* Field declaration */
public int Y; /* Field declaration */
private int length;
public Point(int x, int y) /* Non-parameterless constructor */
{
X = x; Y = y;
length = X + Y;
}
public string ToString() /* Method declaration */
{
return "X" + X + "\n Y:" + Y;
}
public int PointLength /* Read only Property declaration */
{
get { return length; }
}
}

Event

An event is used as a member to provide notification to an object or class. Figure 1-20 demonstrates the possible declaration of an event.

images

Figure 1-20. Possible forms of the interface declaration

Listing 1-57 presents an example of the event in C#.

Listing 1-57. Example of the Event

using System;

namespace Ch01
{
public delegate void EventHandler(string name);
class Program
{
static void Main(string[] args)
{
Book book = new Book();
book.ShowBookName += new EventHandler(book_ShowBookName);
book.Name = "Expert C# 5.0 with .NET Framework 4.5";
Console.WriteLine(book.Name);
}

static void book_ShowBookName(string name)
{
Console.WriteLine(name);
}
}

public class Book
{
public event EventHandler ShowBookName;
private string name;

public string Name
{
set
{
BookEventArgs eventArgs = new BookEventArgs()
{
BookName = "Book name updated...."
};
name = value;
OnNameChanged(eventArgs);
}
get
{
return name;
}

}

protected virtual void OnNameChanged(BookEventArgs args)
{
EventHandler handler = ShowBookName;
if (handler != null)
{
handler(args.BookName);
}
}
}
public class BookEventArgs : EventArgs
{
public string BookName { get; set; }
}

}

In Listing 1-57, the event keyword is used to define an event and produces the following output:

Book name updated....
Expert C# 5.0 with .NET Framework 4.5

Chapter 8 will explore in detail the event.

Interfaces

An interface defines a contract or specification rather than an implementation for its members. When a class or struct implements an interface, it must implement all of its members. Figure 1-21 demonstrates the possible declaration of an interface.

images

Figure 1-21. Possible forms of the interface declaration

Listing 1-58 shows an example of the interface.

Listing 1-58. Example of the Interface

using System;
namespace Ch01
{
class Program
{
static void Main(string[] args)
{
Calculator calculator = new Calculator();
Console.WriteLine(calculator.Add(10, 10)); /* 20 */
Console.WriteLine(calculator.Sub(10, 10)); /* 0 */
Console.WriteLine(calculator.Mul(9, 7)); /* 63 */
}
}

/* interface definition*/
interface IAddition { int Add(int a, int b);} /* Interface declaration */
interface IExAddition{ int Add(int a, int b);} /* Interface declaration */
interface ISubtraction{ int Sub(int a, int b);}/* Interface declaration */
interface IMultiplication :IAddition { int Mul(int a, int b); }
/* Extending Interface declaration */

/* interface implementation*/
public class Calculator :
IAddition,
ISubtraction,
IMultiplication,
IExAddition
/* Multiple interface implementation */
{
public int Add(int a, int b) { return a + b; }

int IExAddition.Add(int a, int b)
/* Explicit interface implementation */
{ return 100 + a + b; }

public int Sub(int a, int b) { return a > b ? a - b : b - a; }

public int Mul(int a, int b)
{
var result = 0;
for (int i = 0; i < a; ++i)
result += Add(0, b);
return result;
}
}
}

This program will produce the output:

20
0
63

In Listing 1-58, the IAddition, IExAddition, ISubtration, and IMultiplication interfaces are defined. The IMultiplication interface is derived from the IAddition interface, and this concept is called “extending an interface in C#.” The Calculator class implements the IAddition, IExAddition, ISubtration, andIMultiplication interfaces. The Calculator class explicitly implements the IExAddition method due to the collision between IAddition and IExAddition interface for the Add method. When a class implements an interface by default, interface members are sealed. To override any member, you need to mark that member as virtual or abstract. Listing 1-59 presents an example of this.

Listing 1-59. Example of Virtual Member

using System;
namespace Ch01
{
class Program
{
static void Main(string[] args)
{
Calculator calculator = new ScientificCalculator();
Console.WriteLine(calculator.Add(10, 10)); /* 120 */
}
}

/* Interface declaration */
interface IAddition { int Add(int a, int b); }

/* Interface implementation */
public class Calculator : IAddition
{
public virtual int Add(int a, int b) { return a + b; }
}

public class ScientificCalculator : Calculator
{
public override int Add(int a, int b) { return 100 + a + b; }
}
}

This program will produce the output:

120

Enum

An enum type contains a set of named constants. Figure 1-22 demonstrates the possible declaration of an enum.

images

Figure 1-22. Possible forms of the enum declaration

The example in Listing 1-60 declares an enum type named Planets with nine constant values, such as Sun, Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, and Neptune.

Listing 1-60. Example of Enum Usage

using System;
namespace Ch01
{
class Program
{
public enum Planets
{
Sun,
Mercury,
Venus,
Earth,
Mars,
Jupiter,
Saturn,
Uranus,
Neptune
}
static void Main()
{
DisplayInformation(Planets.Earth);
DisplayInformation(Planets.Mars);
DisplayInformation(Planets.Jupiter);
}
static void DisplayInformation(Planets planets)
{
switch (planets)
{
case Planets.Earth:
Console.WriteLine("Third planet from the Sun");
break;
case Planets.Mars:
Console.WriteLine("The fourth planet from the Sun");
break;
default:
Console.WriteLine("Please provide valid Planet name");
break;
}
}
}
}

This program will produce the output:

Third planet from the Sun
The fourth planet from the Sun
Please provide valid Planet name

Chapter 6 will explore the details about the enum.

Delegates

A delegate type represents references to methods with a particular parameter list and return type. Delegates make it possible to treat methods as entities that can be assigned to variables and passed as parameters. Figure 1-23 demonstrates the possible declaration of a delegate.

images

Figure 1-23. Possible forms of the delegate declaration

Delegates are similar to the concept of function pointers found in some other languages, for example, C, C++, but unlike function pointers, delegates are object oriented and type safe. Listing 1-61 declares and uses a delegate type named function.

Listing 1-61. Example of the Delegate

using System;
namespace Ch01
{
/* A delegate which will encapsulate a method which accept two parameter
* and return int */
delegate int BinaryOperation(int x, int y);

class Program
{
static void Main(string[] args)
{
Calculate(Add, new Tuple<int, int>(10, 10)); /* 20 */
Calculate(Sub, new Tuple<int, int>(10, 10)); /* 0 */
Calculate(Sub, new Tuple<int, int>(1, 10)); /* 9 */
}

static void Calculate(
BinaryOperation binaryOperation, Tuple<int, int> data)
{
Console.WriteLine(binaryOperation(data.Item1, data.Item2));
}

static int Add(int x, int y)
{
return x + y;
}

static int Sub(int x, int y)
{
return x > y ? x - y : y - x;
}
}
}

This program will produce the output:

20
0
9

Chapter 7 will explore the details about the delegate. In Listing 1-61, a class Tuple has been used to represent a set of values. The tuple, introduced in C# 4.0, is a data structure that has a specific number and sequence of elements. It is used to represent a set of values or to return multiple values from a method.

Exception

A program consists of a sequence of instructions that are to execute a specific operation based on the given data (if any) to produce an expected outcome of the operation. In the execution time, if the instruction cannot do its operation based on the provided data, it will raise an exception for that operation to let the user know about this unexpected behavior. Listing 1-62 shows an example that throws an exception when the system cannot do the divide operation.

Listing 1-62. Example of Division Operation

using System;

namespace Ch01
{
class Program
{
static void Main(string[] args)
{
int a = 10, b = 0;
Division div = new Division();
Console.WriteLine("{0}/{1}={2}", a, b, div.Divide(a, b));
}

public class Division
{
public int Divide(int a, int b)
{
return a / b;
}
}
}
}

The program in Listing 1-45 is intended to do a divide operation based on the data passed via parameter a, b. The divide operation for the a = 10, b = 0; will produce an exception:

Unhandled Exception: System.DivideByZeroException: Attempted to divide by zero. at Ch01.Program.
Division.Divide(Int32 a, Int32 b) in J:\Book\ExpertC#2012\SourceCode\BookExamples\Ch01\Program.
cs:line 18 at Ch01.Program.Main(String[] args) in J:\Book\ExpertC#2012\SourceCode\BookExamples\
Ch01\Program.cs:line 11

The exceptions are handled in a program using the try, catch, and finally statements. Chapter 13 will explore the details about the exception.

Summary

In this chapter we have learned about the C# compilation process and how the JITTER works to JIT the IL code into the native code to make the program understandable by the operating system. You have explored the lexical elements of the C# language such as identifiers, keywords, and comments. You have learned value types and reference types and how you can use these types, and you have explored the parameters and how many different way these can be used in a program to pass data between method calls. The this keyword was analyzed in detail to understand how the CLR passes value for the this keyword as part of parameter passing.

You have learned about the different types of statements used in the C# program, such as the empty statement, expression statement, selection statement (such as, if, switch), iteration statement (such as while, do, for, and foreach), jump statement (such as break, continue), goto statement, and alsotry, using, lock, and yield statements.

This chapter also explored classes, types of classes, fields in classes, methods, properties, index, struct, event, interface, delegate, and exception. With this foundation in place, we move into the next chapter and examine in detail C# objects in memory.