pate c_[1]

321
Pantech Academy of Technical Excellence INTRODUCTION TO .NET 1 .Net Framework Common Language Runtime(CLR) Common Type System(CTS) Common Language Specification(CLS) Microsoft Intermediate Language(MSIL)

Upload: krishna-prasanna

Post on 20-Nov-2014

200 views

Category:

Documents


4 download

TRANSCRIPT

Page 1: PATE C_[1]

Pantech Academy of Technical Excellence

INTRODUCTION TO .NET

1

.Net Framework

Common Language Runtime(CLR)

Common Type System(CTS)

Common Language Specification(CLS)

Microsoft Intermediate Language(MSIL)

Page 2: PATE C_[1]

Pantech Academy of Technical Excellence

Common Language Runtime (CLR)

The Common Language Runtime (CLR) is a core component of Microsoft's .NET

initiative. It is Microsoft's implementation of the Common Language Infrastructure (CLI)

standard, which defines an execution environment for program code. The CLR runs a form of

byte code called the Common Intermediate Language (CIL, previously known as MSIL --

Microsoft Intermediate Language). Central to the .NET Framework is its runtime execution

environment, known as the Common Language Runtime (CLR) or the .NET runtime. Code

running under the control of the CLR is often termed managed code.

Developers using the CLR write code in a language such as C# or VB.NET. At

compile time, a .NET compiler converts such code into CIL code. At runtime, the CLR's just-

in-time compiler converts the CIL code into code native to the operating system.

Alternatively, the CIL code can be compiled to native code in a separate step prior to runtime.

This speeds up all later runs of the software as the CIL-to-native compilation is no longer

necessary. Compilation occurs in two steps in .NET:

1. Compilation of source code to IL

2. Compilation of IL to platform-specific code by the CLR

Although some other implementations of the Common Language Infrastructure run on

non-Windows operating systems, Microsoft's implementation runs only on Microsoft

Windows operating systems. The CLR allows programmers to ignore many details of the

specific CPU that will execute the program. It also provides other important services,

including the following:

Memory management

Thread management

Exception handling

Garbage collection

Security

2

Page 3: PATE C_[1]

Pantech Academy of Technical Excellence

Common Type System (CTS)

The Common Type System (CTS) is a standard that specifies how Type definitions

and specific values of Types are represented in computer memory. It is intended to allow

programs written in different programming languages to easily share information. As used in

programming languages, a Type can be described as a definition of a set of values. The CLI

and the CTS were created by Microsoft, and the Microsoft .NET framework is an

implementation of the standard.

Functions of the Common Type System

To establish a framework that helps enable cross-language integration, type safety,

and high performance code execution.

To provide an object-oriented model that supports the complete implementation of

many programming languages.

To define rules that languages must follow, which helps ensure that objects

written in different languages can interact with each other.

The CTS also defines the rules that ensure that the data types of objects written in

various languages are able to interact with each other.

Type categories

The common type system supports two general categories of types:

Value types

Value types directly contain their data, and instances of value types are either allocated on

the stack or allocated inline in a structure. Value types can be built-in (implemented by the

runtime), user-defined, or enumerations.

3

Page 4: PATE C_[1]

Pantech Academy of Technical Excellence

Reference types

Reference types store a reference to the value's memory address, and are allocated on the

heap. Reference types can be self-describing types, pointer types, or interface types. The type

of a reference type can be determined from values of self-describing types. Self-describing

types are further split into arrays and class types. The class types are user-defined classes,

boxed value types, and delegates.

Example

4

using System;

class Class1

{

public int Value = 0;

}

class Test

{

static void Main( )

{

int val1 = 0;

int val2 = val1;

val2 = 123;

Class1 ref1 = new Class1( );

Class1 ref2 = ref1;

ref2.Value = 123;

Console.WriteLine("Values: {0}, {1}", val1, val2);

Console.WriteLine("Refs: {0}, {1}", ref1.Value, ref2.Value);

}

}

Page 5: PATE C_[1]

Pantech Academy of Technical Excellence

Common Language Specification

The Common Language Specification is a set of base rules to which any language

targeting the CLI (Common Language Infrastructure) should conform in order to interoperate

to other CLS-compliant languages. The CLS rules define a subset of the Common Type

System.

The Common Language Specification (CLS) works with the CTS to ensure language

interoperability. The CLS is a set of minimum standards that all compilers targeting .NET

must support. Since IL is a very rich language, writers of most compilers will prefer to

restrict the capabilities of a given compiler to only support a subset of the facilities offered by

IL and the CTS. That is fine, as long as the compiler supports everything that is defined in the

CLS. For example, let’s look at case sensitivity. IL is case-sensitive. Developers who work

with case-sensitive languages regularly take advantage of the flexibility this case sensitivity

gives them when selecting variable names. Visual Basic .NET, however, is not case sensitive.

The CLS works around this by indicating that CLS-compliant code should not expose any

two names that differ only in their case. Therefore, Visual Basic .NET code can work with

CLS-compliant code.

This example shows that the CLS works in two ways. First, it means that individual

compilers do not have to be powerful enough to support the full features of .NET—this

should encourage the development of compilers for other programming languages that

target .NET. Second, it provides a guarantee that, if you restrict your classes to only exposing

CLS-compliant features, then it is guaranteed that code written in any other compliant

language can use your classes. Within the private implementations of your classes, you can

write whatever non-CLS code you want, because code in other assemblies cannot access this

part of your code anyway. In general, the CLS won’t affect your C# code very much, because

there are very few non–CLS-compliant features of C# anyway. The Common Language

Specification (CLS) is a specification for creating or porting programming languages to that

they are .NET compatible. The CLS uses a Common Type System (CTS). This is a

component of the CLR and provides a common set of data types that are consistent between

all .NET languages.

5

Page 6: PATE C_[1]

Pantech Academy of Technical Excellence

Microsoft Intermediate Language (MSIL)

All .NET source code is compiled to IL. This IL is then converted to machine code at

the point where the software is installed, or at run-time by a Just-In- Time (JIT) compiler.

Microsoft Intermediate Language (MSIL) is a language used as the output of a number of

compilers (C#, VB, .NET, and so forth). The ILDasm (Intermediate Language Disassembler)

program that ships with the .NET Framework SDK (FrameworkSDK\Bin\ildasm.exe) allows

the user to see MSIL code in human-readable format. By using this utility, we can open

any .NET executable file (EXE or DLL) and see MSIL code.

The ILAsm program (Intermediate Language Assembler) generates an executable file

from the MSIL language. We can find this program in the WINNT\Microsoft.NET\

Framework\vn.nn.nn directory.

Any Visual C++ programmer starting with .NET development is interested in what

happens in the low level of the .NET Framework. Learning MSIL gives a user the chance to

understand some things that are hidden from a programmer working with C# or VB.NET.

Knowing MSIL gives more power to a .NET programmer. We never need to write programs

in MSIL directly, but in some difficult cases it is very useful to open the MSIL code in

ILDasm and see how things are done.

A MSIL reference in DOC format is available to a .NET developer and may be found

in the Framework SDK directory: FrameworkSDK\Tool Developers Guide\docs\Partition II

Metadata.doc (Metadata Definition and Semantics). In this file, I found a description of all

MSIL directives such as .entrypoint, .locals, and so on. FrameworkSDK\Tool Developers

Guide\docs\Partition III CIL.doc (CIL Instruction Set) contains a full list of the MSIL

commands.

6

Page 7: PATE C_[1]

Pantech Academy of Technical Excellence

7

Introduction to C#

What is C#?

How Does a C# Application Run?

Does C# have a Runtime Library?

What can I do with C#?

Page 8: PATE C_[1]

Pantech Academy of Technical Excellence

What is C#?

C# (pronounced C Sharp) is one of many .NET programming languages. It is object-

oriented and allows you to build reusable components for a wide variety of application types. 

Microsoft introduced C# on June 26th, 2000 and it became a v1.0 product on Feb 13th 2002.

C# is an evolution of the C and C++ family of languages. However, it borrows features from

other programming languages, such as Delphi and Java. If you look at the most basic syntax

of C# and Java, the code looks very similar, but then again, the code looks a lot like C++. C#

is intended to be a simple, modern, general-purpose, Object oriented Programming Language.

It has an object-oriented syntax based on C++. The most recent version of the language is 3.0

which were released in conjunction with the .Net Framework 3.5 in 2007. The next proposed

version, 4.0, is in development.

In C#, Private is the default accessibility. The accessibility options are:

Public –accessible to all

Private-accessible to containing class

Protected-accessible to containing or derived class

Internal-accessible to code in same assembly

Protected internal means protected or internal

Type members in C# are:

Fields: The state of an object or type

Methods: Constructors, Functions, Properties (smart fields)

Members come in two basic forms

Instance - per object data and methods (default)

Static - per type data and methods (use the static keyword)

8

Page 9: PATE C_[1]

Pantech Academy of Technical Excellence

How Does a C# Application Run?

An important point is that C# is a "managed" language, meaning that it requires the

.NET Common Language Runtime (CLR) to execute. Essentially, as an application that is

written in C# executes, the CLR is managing memory, performing garbage collection,

handling exceptions, and providing many more services that you, as a developer, don't have

to write code for. The C# compiler produces Intermediate Language (IL), rather than machine

language, and the CLR understands IL. When the CLR sees the IL, it Just-In-Time (JIT)

compiles it, method by method, into compiled machine code in memory and executes it. As

mentioned previously, the CLR manages the code as it executes.

Because C# requires the CLR, you must have the CLR installed on your system. All

new Windows operating systems ship with a version of the CLR and it is available via

Windows Update for older systems. The CLR is part of the .NET, so if you see updates for

the .NET Framework Runtime, it contains the CLR and .NET Framework Class Library

(FCL). It follows that if you copy your C# application to another machine, then that machine

must have the CLR installed too.

Does C# have a Runtime Library?

Instead of a runtime library (such as APIs for file I/O, string handling, etc.) being

dedicated to a single language, .NET ships with a .NET Framework Class Library (FCL),

which includes literally tens of thousands of reusable objects. Since all .NET languages target

the CLR with the same IL, all languages can use the FCL. This shortens the learning curve

for any developer moving from one .NET language to another, but also means that Microsoft

is able to add many more features because there is only one FCL, rather than a separate

implementation for common features in every programming language.

Similarly, 3rd party software vendors can write managed code that any .NET

developer, regardless of language, can use. In addition to all of the services you would expect

of a runtime library, such as collections, file I/O, networking, etc., the FCL includes the APIs

for all of the other .NET technologies, such as for desktop and Web development.

9

Page 10: PATE C_[1]

Pantech Academy of Technical Excellence

What can I do with C#?

C# is only a programming language. However, because C# targets the CLR and has

access to the entire FCL, there's a lot you can do. You can write desktop applications with

Windows Forms, Windows Presentation Foundation (WPF), or even Console applications.

For the Web, you can write ASP.NET and Silverlight applications in addition to enabling

systems to communicate with Web Services with Windows Communications Foundation

(WCF). When you need to access data, there is both ADO.NET and LINQ. Of course, these

are only a few of the technologies available and as a general purpose programming language;

you can do a lot more than this with C#.

10

Page 11: PATE C_[1]

Pantech Academy of Technical Excellence

C#.NET LANGUAGE BASICS

11

Data Types and Variables

Data Types

Integer Types

Boolean

Floating Point Types

Decimal Types

Character and Strings

Variables

Static Variables

Variable of Instance

Array’s Elements

Local Variables

Constants

Page 12: PATE C_[1]

Pantech Academy of Technical Excellence

Data Types

Integer Types:

C# supports eight predefined integer types.

C# supports a rich palette of signed and unsigned integer types ranging in size from 8 to 64

bits. In C#, an int is always a 32-bit signed integer.

Boolean Types:

The C# bool type is used to contain Boolean values of either true or false.

Name CTS Type Values

bool System. Boolean True or False

12

Name CTS Type Description Range (min: max)sbyte System.SByte 8-bit signed integer -128:127 (-27:27-1)short System.Int16 16-bit signed integer -32,768:32,767 (-215:215-1)int System.Int32 32-bit signed integer -2, 147, 483,64 :

2,147,483,647(-231:231-1)long System.Int64 64-bit signed integer -9,223,372,036,854,775,808:

9,223,372,036,854,775,807 (-263:263-1)

Byte System.Byte 8-bit unsigned integer 0:255 (0:28-1)ushort System.UInt16 16-bit unsigned integer 0:65,535 (0:216-1)uint System.UInt32 32-bit unsigned integer 0:4,294,967,295 (0:232-1)ulong System.UInt64 64-bit unsigned integer 0:18,446,744,073,709,551,615

(0:264-1)

Page 13: PATE C_[1]

Pantech Academy of Technical Excellence

Floating Point and Decimal Types:

A C# Floating Point type is either float or double. It’s used when you need to perform

operations requiring fractional representations. Decimal Types should be used when

representing financial or money values.

Type Size (in bits) Precision Range

Float 32 7 digits 1.5 x 10-45 to 3.4 x 1038

Double 64 15-16 digits 5.0 x 10-324 to 1.7 x 10308

Decimal 128 28-29 decimal places 1.0 x 10-28 to 7.9 x 1028

Character and String Types:

A char type is used to represent Unicode Characters. A variable of type char

represents a single 16-bit Unicode Character. There are no implicit conversions from char to

other data types available. That means treating a char variable just as another integral data

type is not possible.

A string is a sequence of text characters. You typically create a string with a string

literal, enclosed in quotes: "This is an example of a string". C# has a special syntax where

characters can be escaped to represent non-printable characters.

Below Table shows a list of common escape sequences.

Escape Sequence Meaning

\' Single Quote

\" Double Quote

\\ Backslash

\0 Null, not the same as the C# null value

\a Bell

\b Backspace

\f form Feed

13

Page 14: PATE C_[1]

Pantech Academy of Technical Excellence

\n Newline

\r Carriage Return

\t Horizontal Tab

\v Vertical Tab

Variables

Variables in c# using the following syntax.

Syntax:

datatype identifier;

For Example:

int i;

Once it has been declared, We can assign a value to the variable using the assignment

operator,=;

Eg: i=10;

We can also declare the variable and initialize its value at the same time.

Static Variables:

Static Variables will be alive throughout the life of a program. It can be declared

using static modifier.

Variable of Instance:

  An Instance variable is a variable declared without static modifier. Usually it is declared

inside a class or structure definition.

14

Page 15: PATE C_[1]

Pantech Academy of Technical Excellence

Array Elements:

An array is a data structure that contains a number of variables. The new operator is

used to create the array and initialize the array elements to their default values. C# supports:

One-dimensional arrays,

Multidimensional arrays (rectangular arrays)

Arrays of arrays (jagged arrays).

The array indexes start as zero. When declaring arrays, the square bracket [ ] must

come after the type, not the identifiers, In C#, arrays are derived from the System.Array class.

Notes:

One-dimensional Arrays

For Example:

int[ ] table.

int[ ] numbers = new int[20]; we can initialize arrays very simply:

int[ ] numbers = {0, 1, 2, 3, 5}; This is identical to the complete initialization

statement:

int [ ] numbers = new int[ ] {0, 1, 2, 3, 5};

Multi-dimensional Arrays

Arrays can have more one dimension. C# also supports multi-dimensional arrays.

For Example:

Two-dimensional arrays: int[,] y;

15

Arrays in C# use square brackets, not parentheses. C++ users will be familiar with the square

brackets, but should check the code we present here carefully because C# syntax for actually

declaring array variables is not the same as C++ syntax

Page 16: PATE C_[1]

Pantech Academy of Technical Excellence

Three-dimensional arrays: int[,,] y;

Figure: Usage Of multi-dimensional arrays

Jagged Arrays

A jagged array is an array whose elements are arrays. The elements of a jagged

array can be of different dimensions and sizes. A jagged array is sometimes called an "array

of arrays."

For Example:

16

Using System;Class multi{

Public static void main(){int[ ,]x;x=new int[4,4];x[0,0] = 1;x[1,1] = 1;x[2,2] = 1;x[3,3] = 1;Console.WriteLine(x[0,0]+” “+x[0,1]+” “+x[0,2]+” “x[0,3]);Console.WriteLine(x[1,1]+” “+x[1,1]+” “+x[1,2]+” “x[1,3]);Console.WriteLine(x[2,2]+” “+x[2,1]+” “+x[2,2]+” “x[2,3]);Console.WriteLine(x[3,3]+” “+x[3,1]+” “+x[3,2]+” “x[3,3]);}

}

Page 17: PATE C_[1]

Pantech Academy of Technical Excellence

Figure: Usage of Jagged arrays

Local Variables and Constants

Local Variables can optionally be constant (const). Constant Local Variables are

stored in the assembly data region, While non-constant local variables are stored on (or

17

Using System;Class Jagged{

int [ ][ ] x=new int[2][ ];void set ( ){x[0]=new int[2];x[1]=new int[2];x[0][0]=1;x[0][1]=2;}void show ( ){

for (int i=0; i<2; i++){

for (j=0; j<2; j++){Console.WriteLine(x[i] [j]);}

}}

Public static void main ( ){Jagged j=new Jagged ( );j.set( );j.show( );}

}

Page 18: PATE C_[1]

Pantech Academy of Technical Excellence

referenced from) the stack. They thus have both a scope and extend of the method or

statement block that declares them.

The const keyword is used to modify a declaration of a field or local variable. It

specifies that the value of the field or the local variable is constant, which means it cannot be

modified.

For example:

const int x = 0;

public const double gravitationalConstant = 6.673e-11;

private const string productName = "Visual C#";

The type of a constant declaration specifies the type of the members introduced by the

declaration. A constant expression must yield a value of the target type or of a type that can

be implicitly converted to the target type. A constant expression is an expression that can be

fully evaluated at compile time. Therefore, the only possible values for constants of reference

types are string and null. The constant declaration can declare multiple constants, such as:

public const double x = 1.0, y = 2.0, z = 3.0;

The static modifier is not allowed in a constant declaration. A constant can participate

in a constant expression, as follows:

public const int c1 = 5;

public const int c2 = c1 + 100;

Notes

18

The readonly keyword is different from the const keyword. A const field can only be

initialized at the declaration of the field. A readonly field can be initialized either at the

declaration or in a constructor. Therefore, readonly fields can have different values depending

on the constructor used. Also, while a const field is a compile-time constant, the readonly

field can be used for run-time constants, as in this line:

public static readonly uint l1 = (uint)DateTime.Now.Ticks;

Page 19: PATE C_[1]

Pantech Academy of Technical Excellence

19

Type Conversions

What is Conversion?

Widening Conversion

Narrowing Conversion

Boxing and Un-Boxing Conversion

Interface Conversion

Implicit Conversion

Explicit Conversion

Page 20: PATE C_[1]

Pantech Academy of Technical Excellence

What is Conversions?

Conversion is the process of changing a value from one type to another. Conversions

may either be widening or narrowing.

Widening Conversions

When a particular data type is converted to a data type that is capable of storing more

data than the source data type is referred to as widening conversion. The simple examples of

widening conversion can be Numeric type conversions in the direction Byte, Short, Integer,

Long, Decimal, Single, Double, here every type listed to the right of a type is capable of

storing more data than its left listed type. If we takes the case of reference data types then

Conversions from any derived type to one of its base types is also referred to as widening

conversion. Widening conversion never cause overflow.

Narrowing Conversions

A narrowing conversion occurs when a variable is converted to a type that is not

capable of storing the data held by the source data type variable. These conversions are

known to possibly lose information and conversions across domains of types sufficiently

different to merit narrowing notation. These means narrowing conversions entail loss of

information and may fail.

Following list defines different types of conversion:

Identity conversion

An identity conversion converts from any type to the same type. This conversion

exists only such that an entity that already has a required type can be said to be convertible to

that type.

20

Page 21: PATE C_[1]

Pantech Academy of Technical Excellence

Numeric conversions: Some examples of numeric conversions are:

From sbyte to short, int, long, float, double, or decimal.

From byte to short, ushort, int, uint, long, ulong, float, double, or decimal.

From short to int, long, float, double, or decimal.

Etc.

Reference conversions

These are conversion from one reference type to another. Reference conversions,

implicit or explicit, never change the referential identity of the object being converted. In

other words, while a reference conversion may change the type of the reference, it never

changes the type or value of the object being referred to.

Boxing and Un-Boxing Conversions

A boxing conversion permits any value-type to be converted to the type object or to

any interface-type implemented by the value-type. Boxing a value of a value-type consists of

allocating an object instance and copying the value-type value into that instance. Unboxing is

an explicit conversion from the type object to a value type or from an interface type to a value

type that implements the interface.

An unboxing operation consists of:

- Checking the object instance to make sure it is a boxed value of the given value type.

- Copying the value from the instance into the value-type variable.

Interface Conversion

Converting an interface to a value type consists of copying the value in the interface

instance to the target variable (which may be a temporary).

21

Page 22: PATE C_[1]

Pantech Academy of Technical Excellence

Implicit Conversion

The implicit keyword is used to declare an implicit user-defined type conversion

operator.

Syntax:

class SomeType

{

public static implicit operator int(SomeType typ)

{

// code to convert from SomeType to int

}

}

Implicit conversion operators can be called implicitly, without being specified by explicit

casts in the source code.

SomeType x;

int i = x; // implicitly call SomeType’s implicit conversion function that returns int value.

Since the implicit conversion occurs with out user specifying the casting type, may

sometimes lead to confusing code.

The following implicit conversions are classified as standard implicit conversions:

Identity conversions

Implicit numeric conversions

Implicit reference conversions

22

Page 23: PATE C_[1]

Pantech Academy of Technical Excellence

Boxing conversions

Implicit constant expression conversions

The standard implicit conversions specifically exclude user-defined implicit conversions.

// hold any value an int can hold, and more!

int num = 2147483647;

long bigNum = num;

Explicit Conversion

Explicit conversion is performed using casting. Casting occurs when you prefix a

conversion with a data type that defines the type of the conversion you want to perform. The

explicit keyword is used to declare an explicit user-defined type conversion operator. The set

of explicit conversions includes all implicit conversions.

Syntax:

class SomeType

{

public static explicit operator SomeType (int i)

{

// code to convert from int to SomeType

}

}

Unlike implicit conversion, explicit conversion operators must be invoked via a cast.

int i;

SomeType x = (SomeType) i;

Omitting the cast results in a compile-time error. Using explicit prevents the compiler from

silently invoking the conversion operation with possibly unforeseen consequences.

23

Page 24: PATE C_[1]

Pantech Academy of Technical Excellence

The following conversions are classified as explicit conversions:

All implicit conversions.

Explicit numeric conversions.

Explicit enumeration conversions.

Explicit reference conversions.

Explicit interface conversions.

Unboxing conversions.

User-defined explicit conversions

For Example:

24

class Test

{

static void Main()

{

double x = 1234.7;

int a;

// Cast double to int.

a = (int)x;

System. Console.WriteLine (a);

}

}

// Output: 1234

Page 25: PATE C_[1]

Pantech Academy of Technical Excellence

25

Boxing and Un-Boxing

What is boxing and Un-Boxing?

Example Program

Boxing Conversion

Un-Boxing Conversion

Page 26: PATE C_[1]

Pantech Academy of Technical Excellence

What is Boxing and Un-Boxing?

Boxing and unboxing is an essential concept in C# type system. With Boxing and

unboxing one can link between value-types and reference-types by allowing any value of a

value-type to be converted to and from type object. Boxing and unboxing enables a unified

view of the type system wherein a value of any type can ultimately be treated as an object.

Converting a value type to reference type is called Boxing. Unboxing is an explicit

operation. C# provides a unified type system. All types including value types derive from the

type object. It is possible to call object methods on any value, even values of primitive types

such as int.

Example for Boxing and Un-Boxing

Figure: Usage Of Boxing and Un-Boxing

Here, in this example an int value can be converted to object and back again to int.

This example shows both boxing and unboxing. When a variable of a value type

needs to be converted to a reference type, an object box is allocated to hold the value, and the

value is copied into the box. Unboxing is just the opposite. When an object box is cast back

to its original value type, the value is copied out of the box and into the appropriate storage

location.

26

class Test{

static void Main() {

int i = 1;object o = i; // boxingint j = (int) o; // unboxing

}}

Page 27: PATE C_[1]

Pantech Academy of Technical Excellence

Boxing Conversions

A Boxing conversion permits any value-type to be implicitly converted to the type

object or to any interface-type implemented by the value-type. Boxing a value of a value-type

consists of allocating an object instance and copying the value-type value into that instance.

For example any value-type G, the boxing class would be declared as follows:

class vBox

{

G value;

G_Box(G g)

{

value = g;

}

}

Boxing of a value v of type G now consists of executing the expression new G_Box (v), and

returning the resulting instance as a value of type object.

Thus, the statements

int i=12;

object box = i;

Conceptually correspond to

int i=12;

object box = new int_Box(i);

Boxing classes like G_Box and int_Box above don’t actually exist and the dynamic

type of a boxed value isn’t actually a class type. Instead, a boxed value of type G has the

dynamic type G, and a dynamic type check using this operator can simply reference type G.

27

Page 28: PATE C_[1]

Pantech Academy of Technical Excellence

For Example:

int i=12;

object box=i;

if (box is int)

{

Console.Write("Box contains an int");

}

will output the string. ”Box contains an int”.

A boxing conversion implies making a copy of the value being boxed. This is different from

a conversion of a reference-type to type object, in which the value continues to reference the

same instance and simply is regarded as the less derived type object.

For example, given the declaration

struct Point

{

public int x, y;

public Point(int x, int y)

{

this.x = x;

this.y = y;

}

}

The following statements

Point p=new Point (10,10);

object box =p;

p.x=20;

Console.Write(((Point)box).x);

28

Page 29: PATE C_[1]

Pantech Academy of Technical Excellence

will output the value 10 on the console because the implicit boxing operation that occurs in

the assignment of p to box causes the value of p to be copied. Had Point instead been

declared a class, the value 20 would be output because p and box would reference the same

instance.

Un-Boxing Conversion

An unboxing conversion permits an explicit conversion from type object to any value-

type or from any interface-type to any value-type that implements the interface-type. An

unboxing operation consists of first checking that the object instance is a boxed value of the

given value-type, and then copying the value out of the instance. Unboxing conversion of an

object box to a value-type G consists of executing the expression ((G_Box)box).value.

Thus, the statements object box =12;

int i = (int) box;

Conceptually correspond to

Object box=new int_Box (12);

int i = ((int_Box) box).value;

For an unboxing conversion to a given value-type to succeed at run-time, the value of the

source argument must be a reference to an object that was previously created by boxing a

value of that value-type. If the source argument is null or a reference to an incompatible

object, an InvalidCastException is thrown.

29

Page 30: PATE C_[1]

Pantech Academy of Technical Excellence

30

Conditional Statements

If-Else Statement

Nested If Statement

Switch Statement

Page 31: PATE C_[1]

Pantech Academy of Technical Excellence

Conditional Statements

Conditional statements allow us to branch our code depending on whether certain

conditions are met or on the value of an expression. C# has two constructs for branching code

— the if statement, which allows us to test whether a specific condition is met, and the switch

statement, which allows us to compare an expression with a number of different values.

If-Else Statement

The most commonly used conditional statement is the If… Else block, in which a

statement is evaluated to true or false and depending on the result, a different section of code

is executed. In this sample the statement checks if the condition is true, if it is it executes the

first block of code. If the condition is false then it executes the second.

SYNTAX:

if (condition)

statement(s)

else

statement(s)

Example:

Figure: Sample If… Else statement

Nested If Statement

31

int x = 5;

if (x >= 3)

{

Console.WriteLine ("X is greater than or equal to 3.");

}

else

{

Console.WriteLine ("X is less than 3.");

}

Page 32: PATE C_[1]

Pantech Academy of Technical Excellence

If you have multiple scenarios, you can nest if… else statements:

Example:

Figure: Nested If Statement

Switch Statement

The switch statement is a control statement that handles multiple selections and

enumerations by passing control to one of the case statements within its body .The

switch...case statement is good for selecting one branch of execution from a set of mutually

exclusive ones. It will be familiar to C++ and Java programmers and is similar to the Select

Case statement in Visual Basic. It takes the form of a switch argument followed by a series of

case clauses. When the expression in the switch argument evaluates to one of the values

beside a case clause, the code immediately following the case clause executes. We mark the

end of the code for each case using the break statement. We can also include a default case in

the switch statement, which will execute if the expression evaluates to none of the other

cases.

The following switch statement tests the value of the integer A variable:

Example:

32

if (dayOfWeek = Monday)

Console.WriteLine ("Today is Monday");

else if (dayOfWeek = Tuesday)

Console.WriteLine ("Today is Tuesday");

else if (dayOfWeek = Wednesday)

Console.WriteLine ("Today is Wednesday");

else if (dayOfWeek = Thursday)

Console.WriteLine ("Today is Thursday");

else if (dayOfWeek = Friday)

Console.WriteLine ("Today is Friday");

Page 33: PATE C_[1]

Pantech Academy of Technical Excellence

Notes:

33

switch (integerA){case 1:Console.WriteLine (“integerA =1”);break;case 2:Console.WriteLine (“integerA =2”);break;case 3:Console.WriteLine (“integerA =3”);break;default:Console.WriteLine (“integerA is not 1, 2, or 3”);break;}

The case values must be constant expressions; variables are not permitted. Though the switch...case statement should be familiar to C and C++ programmers, C#’s switch.. case is a bit safer than its C++ equivalent. Specifically, it prohibits fall-through conditions in almost all cases. This means that if a case clause is fired early on in the block, later clauses cannot be fired unless you use a goto statement to mark that you want them fired too. The compiler enforces this restriction by flagging every case clause that is not equipped with a break statement as an error similar to this: Control cannot fall through from one case label (‘case 2:’) to another 49

Page 34: PATE C_[1]

Pantech Academy of Technical Excellence

34

Looping Statements

while Loop

do-while Loop

for Loop

foreach Loop

Page 35: PATE C_[1]

Pantech Academy of Technical Excellence

Looping Statement

C# provides four different loops for, while, do...while, and foreach that allow us to

execute a block of code repeatedly until a certain condition is met.

C# provides a number of the common loop statements:

while

do-while

for

foreach

While Loop

A 'while' loop executes a statement, or a block of statements wrapped in curly braces,

repeatedly until the condition specified by the boolean expression returns false. The

statements can be any valid C# statements.

Syntax:

while (condition)

statement[s];

For Example:

Produces the following output: 0 1 2

do-while Loop

35

int a = 0;

while (a < 3)

{

System. Console.WriteLine (a);

a++;

}

do

{

Console.WriteLine(number);

number = number + 1;

} while(number < 5);

Page 36: PATE C_[1]

Pantech Academy of Technical Excellence

The do...while loop is the post-test version of the while loop. It does the same thing

with the same syntax as do...while in C++ and Java, and the same thing as Loop...While in

Visual Basic. This means that the loop’s test condition is evaluated after the body of the loop

has been executed. Consequently, do...while loops are useful for situations in which a block

of statements must be executed at least one time.

Syntax:

do

{

statement[s];

}while (condition);

For Example:

for Loop

C# for loops provides a mechanism for iterating through a loop where we test whether

a particular Condition holds before we perform iteration.

Syntax:

for (initializer; condition; iterator)

statement(s)

Where:

36

do

{

Console.WriteLine(number);

number = number + 1;

} while(number < 5);

Page 37: PATE C_[1]

Pantech Academy of Technical Excellence

The initializer is the expression evaluated before the first loop is executed (usually

initializing a local variable as a loop counter).

The condition is the expression that is checked before each new iteration of the

loop (this must evaluate to true for another iteration to be performed).

The iterator is an expression that will be evaluated after each iteration (usually

incrementing the loop counter). The iterations end when the condition evaluates to

false.

The for loop is a so-called pre-test loop, because the loop condition is evaluated

before the loop statements are executed, and so the contents of the loop won’t be executed at

all if the loop condition is false. The for loop is excellent for repeating a statement or a block

of statements for a predetermined number of times. The following example is typical of the

use of a for loop.

foreach Loop

The foreach statement repeats a group of embedded statements for each element in an

array or an object collection. The foreach statement is used to iterate through the collection

to get the desired information, but should not be used to change the contents of the collection

to avoid unpredictable side effects.

Notes:

Figure: Usage Of foreach Loop

37

class ForEachTest

{

static void Main(string[ ] args)

{

int[ ] fibarray = new int[ ] { 0, 1, 2, 3, 5, 8, 13 };

foreach (int i in fibarray)

{

System.Console.WriteLine(i);

}

}

}

The embedded statements continue to execute for each element in the array or collection. After

the iteration has been completed for all the elements in the collection, control is transferred to the

next statement following the foreach block. At any point within the foreach block, you can break

out of the loop using the break keyword, or step directly to the next iteration in the loop by using

the continue keyword. A foreach loop can also be exited by the goto, return, or throw statements.

Page 38: PATE C_[1]

Pantech Academy of Technical Excellence

38

Page 39: PATE C_[1]

Pantech Academy of Technical Excellence

39

Methods in C#

Method.

Method Parameters

Return Values

Page 40: PATE C_[1]

Pantech Academy of Technical Excellence

Method

A Method is a code block containing a series of statements. In C#, every executed

instruction is done so in the context of a method. Methods are declared within a class or struct

by specifying the access level, the return value, the name of the method, and any method

parameters. Method parameters are surrounded by parentheses, and separated by commas.

Empty parentheses indicate that the method requires no parameters. All C# programs are

constructed from a number of classes and almost all the classes will contain methods. A class

when instantiated is called an object. Object-oriented concepts of programming say that the

data members of each object represent its state and methods represent the object behavior.

For Example:

The following Class contains three methods:

Calling a method on an object is similar to accessing a field. After the object name, add a

period, the name of the method, and parentheses. Arguments are listed within the

parentheses, and separated by commas. The methods of the Motorcycle class can therefore be

called like this:

Motorcycle moto = new Motorcycle();

moto.StartEngine();

moto.AddGas(15);

moto.Drive(5, 20);

40

class Motorcycle

{

public void StartEngine( ) { }

public void AddGas(int gallons) { }

public int Drive(int miles, int speed) { return 0; }

}

Page 41: PATE C_[1]

Pantech Academy of Technical Excellence

Method Parameters

In the above example, passing arguments to a method is simply providing them in the

parentheses when calling a method. To the method being called, the incoming arguments are

called parameters.

The parameters a method receives are also provided in a set of parentheses, but the

type and a name for each parameter must be specified. The name does not have to be the

same as the argument.

For Example:

Here a method called PassesInteger passes an argument to a method called

TakesInteger. Within PassesInteger, the argument is named fortyFour, but in TakesInteger,

this is a parameter named i. This parameter exists only within the TakesInteger method. Any

number of other variables can be named i, and they can be of any type, so long as they are not

parameters or variables declared inside this method.

By default, when a value type is passed to a method, a copy is passed instead of the

object itself. Because they are copies, any changes made to the parameter have no effect

within the calling method. Value types get their name from the fact that a copy of the object

is passed instead of the object itself. The value is passed, but not the same object.

41

public static void PassesInteger()

{

int fortyFour = 44;

TakesInteger(fortyFour);

}

static void TakesInteger(int i)

{

i = 33;

}

Page 42: PATE C_[1]

Pantech Academy of Technical Excellence

Passing Parameters

In C#, parameters can be passed either by value or by reference. Passing parameters

by reference allows function members, methods, properties, indexers, operators, and

constructors, to change the value of the parameters and have that change persist. To pass a

parameter by reference, use the ref or out keyword.

For Example:

Passing Value-Type Parameters

A value-type variable contains its data directly as opposed to a reference-type

variable, which contains a reference to its data. Therefore, passing a value-type variable to a

method means passing a copy of the variable to the method. Any changes to the parameter

that take place inside the method have no affect on the original data stored in the variable. If

you want the called method to change the value of the parameter, you have to pass it by

reference, using the ref or out keyword.

Example:

Passing Value Types by Value

The following example demonstrates passing value-type parameters by value. The

variable n is passed by value to the method SquareIt. Any changes that take place inside the

method have no affect on the original value of the variable.

42

// Passing by value

static void Square(int x)

{

// code...

}

// Passing by reference

static void Square(ref int x)

{

// code...

}

Page 43: PATE C_[1]

Pantech Academy of Technical Excellence

Output

Output

The value before calling the method: 5

The value inside the method: 25

The value after calling the method: 5

Passing Reference-Type Parameters

A variable of a reference type does not contain its data directly; it contains a reference

to its data. When you pass a reference-type parameter by value, it is possible to change the

data pointed to by the reference, such as the value of a class member. However, you cannot

change the value of

the reference itself; that is, you cannot use the same reference to allocate memory for a new

class and have it persist outside the block.

43

class PassingValByVal

{

static void SquareIt(int x)

// The parameter x is passed by value.

// Changes to x will not affect the original value of x.

{

x *= x;

System.Console.WriteLine("The value inside the method: {0}", x);

}

static void Main ( )

{

int n = 5;

System.Console.WriteLine("The value before calling the method: {0}", n);

SquareIt(n); // Passing the variable by value.

System.Console.WriteLine("The value after calling the method: {0}", n);

}

}

Page 44: PATE C_[1]

Pantech Academy of Technical Excellence

Example:

Passing Reference Types by Value

The following example demonstrates passing a reference-type parameter, arr, by

value, to a method, Change. Because the parameter is a reference to arr, it is possible to

change the values of the array elements. However, the attempt to reassign the parameter to a

different memory location only works inside the method and does not affect the original

variable, arr.

Output

Inside Main, before calling the method, the first element is: 1

Inside the method, the first element is: -3

Inside Main, after calling the method, the first element is: -3

Return Values

Methods can return a value to the caller. If the return type, the type listed before the

method name, is not void, then the method can return the value using the return keyword. A

statement with the keyword return followed by a value that matches the return type will

44

class PassingRefByVal { static void Change(int[ ] pArray) { pArray[0] = 888; // This change affects the original element. pArray = new int[5] {-3, -1, -2, -3, -4}; // This change is local. System.Console.WriteLine("Inside the method, the first element is: {0}", pArray[0]); }

static void Main() { int[ ] arr = {1, 4, 5}; System.Console.WriteLine("Inside Main, before calling the method, the first element is: {0}", arr [0]);

Change(arr); System.Console.WriteLine("Inside Main, after calling the method, the first element is: {0}", arr [0]); }}

Page 45: PATE C_[1]

Pantech Academy of Technical Excellence

return that value to the method caller. The return keyword also stops the execution of the

method. If the return type is void, a return statement with no value is still useful to stop the

execution of the method. Without the return keyword, the method will stop executing when it

reaches the end of the code block. Methods with a non-void return type are required to use

the return keyword to return a value.

For Example:

These two methods use the return keyword to return integers:

To use a value returned from a method, the calling method can use the method call itself

anywhere a value of the same type would suffice. You can also assign the return value to a

variable.

For example:

The following two code examples accomplish the same goal:

45

class SimpleMath{ public int AddTwoNumbers(int number1, int number2) { return number1 + number2; }

public int SquareANumber(int number) { return number * number; }}

int result = obj.AddTwoNumbers(1, 2);

obj.SquareANumber(result);

obj.SquareANumber(obj.AddTwoNumbers(1, 2));

Page 46: PATE C_[1]

Pantech Academy of Technical Excellence

46

Properties

Properties.

Property Declaration

Example Program

Overview of Properties

Page 47: PATE C_[1]

Pantech Academy of Technical Excellence

Properties

Properties are members that provide a flexible mechanism to read, write, or compute

the values of private fields. Properties can be used as if they are public data members, but

they are actually special methods called accessors. This enables data to be accessed easily

and still helps promote the safety and flexibility of methods.

Property Declaration

Property declaration takes one of the following forms:

[attributes] [modifiers] type identifier {accessor-declaration}

[attributes] [modifiers] type interface-type.identifier {accessor-declaration}

where:

attributes (Optional) -Additional declarative information.

modifiers(Optional) - The allowed modifiers are new, static, virtual, abstract,

override

o and a valid combination of the four access modifiers.

type - The property type, which must be at least as accessible as the

o property itself.

identifier - The Property name

accessor-declaration - declaration of the property accessors, which are used to read

and

o write the property.

interface-type - the interface in a fully qualified property name.

Example for Property

A property declared using the static modifier is classified as a static property;

otherwise, it is classified as an instance property. Like other static members, a static property

is not associated with a specific instance and cannot be referenced through an instance.

Instead, it is associated with the type and can only be referenced through the type name

47

Page 48: PATE C_[1]

Pantech Academy of Technical Excellence

Output:

Employee number: 101

Employee name: Claude Vige

48

using System;public class Employee { public static int numberOfEmployees; private static int counter; private string name; public string Name // A read-write instance property: { get { return name; } set { name = value; } } public static int Counter // A read-only static property: { get { return counter; } } // Constructor: public Employee() { // Calculate the employee's number: counter = ++counter + numberOfEmployees; }}public class MainClass{ public static void Main() { Employee.numberOfEmployees = 100; Employee e1 = new Employee(); e1.Name = "Claude Vige"; Console.WriteLine("Employee number: {0}", Employee.Counter); Console.WriteLine("Employee name: {0}", e1.Name); }}

Page 49: PATE C_[1]

Pantech Academy of Technical Excellence

Properties Overview

Properties enable a class to expose a public way of getting and setting values, while

hiding implementation or verification code.

A get property accessor is used to return the property value, and a set accessor is used

to assign a new value. These accessors can have different access levels.

The value keyword is used to define the value being assigned by the set accessor.

Properties that do not implement a set accessor are read only.

For simple properties that require no custom accessor code, consider the option of

using auto-implemented properties.

Arrays

An array is a data structure that contains a number of variables. The new operator is

used to create the array and initialize the array elements to their default values.

C# supports:

One-dimensional arrays,

Multidimensional arrays (rectangular arrays)

Arrays of arrays (jagged arrays).

We discussed this topic previously please refer it.

49

Page 50: PATE C_[1]

Pantech Academy of Technical Excellence

50

Indexers

Indexer

Indexer Declaration

Example for Indexer

Overview of Indexer

Comparison between properties and Indexer

Page 51: PATE C_[1]

Pantech Academy of Technical Excellence

Indexers

Indexers allow instances of a class or struct to be indexed just like arrays. Indexers

resemble properties except that their accessors take parameters.

Indexer Declaration

Indexers allow you to index a class or a struct instance in the same way as an array.

To declare an indexer, use the following:

[attributes] [modifiers] indexer-declarator {accessor-declarations}

The indexer-declarator takes one of the forms:

type this [formal-index-parameter-list]

type interface-type.this [formal-index-parameter-list]

The formal-index-parameter takes the form:

[attributes] type identifier

where:

attributes (Optional) -Additional declarative information.

modifiers (Optional) -Allowed modifiers are new, virtual, sealed, override,

abstract, extern, and a valid combination of the

four access

modifiers

indexer-declarator - Includes the type of the element introduced by the

indexer, this, and the formal-index-parameter-

list. If the indexer is an explicit interface

member implementation, the interface-type is

included.

type -A type name.

interface-type -The interface name.

formal-index-parameter-list -Specifies the parameters of the indexer. The parameter

51

Page 52: PATE C_[1]

Pantech Academy of Technical Excellence

includes optional attributes, the index type, and the

index identifier. At least one parameter must be

specified. The parameter modifiers out and ref are not

allowed.

accessor-declarations -The indexer accessors, which specify the executable

statements associated with reading and writing

indexer

elements

identifier -The parameter name.

get Accessor

The get accessor body of an indexer is similar to a method body. It returns the type of

the indexer. The get accessor uses the same formal-index-parameter-list as the indexer.

For Example:

get

{

return myArray[index];

}

set Accessor

The set accessor body of an indexer is similar to a method body. It uses the same

formal-index-parameter-list as the indexer, in addition to the value implicit parameter.

For Example:

set

{

myArray[index] = value;

}

Notes:

52

Page 53: PATE C_[1]

Pantech Academy of Technical Excellence

Example for Indexer

Output:

53

The type of an indexer and each of the types referenced in the formal-index-parameter-list must be

at least as accessible as the indexer itself. The signature of an indexer consists of the number and

types of its formal parameters. It does not include the indexer type or the names of the formal

parameters. If you declare more than one indexer in the same class, they must have different

signatures. An indexer value is not classified as a variable; therefore, it is not possible to pass an

indexer value as a ref or out parameter.

// cs_keyword_indexers.csusing System;class IndexerClass { private int [ ] myArray = new int[100]; public int this [int index] // Indexer declaration { get { // Check the index limits. if (index < 0 || index >= 100) return 0; else return myArray[index]; } set { if (!(index < 0 || index >= 100)) myArray[index] = value; } }}public class MainClass { public static void Main() { IndexerClass b = new IndexerClass(); // Call the indexer to initialize the elements #3 and #5. b[3] = 256; b[5] = 1024; for (int i=0; i<=10; i++) { Console.WriteLine ("Element #{0} = {1}", i, b[i]); } }}

Page 54: PATE C_[1]

Pantech Academy of Technical Excellence

Element #0 = 0

Element #1 = 0

Element #2 = 0

Element #3 = 256

Element #4 = 0

Element #5 = 1024

Element #6 = 0

Element #7 = 0

Overview of Indexer

Indexers enable objects to be indexed in a similar manner to arrays.

A get accessor returns a value. A set accessor assigns a value.

This keyword is used to define the indexers.

The value keyword is used to define the value being assigned by the set indexer.

Indexers do not have to be indexed by an integer value; it is up to you how to define

the specific look-up mechanism.

Indexers can be overloaded.

Indexers can have more than one formal parameter, for example, when accessing a

two-dimensional array.

Comparison between Properties and Indexer

Indexers are similar to properties. Except for the differences shown in the following

table, all of the rules defined for property accessors apply to indexer accessors as well.

Property Indexer

54

Page 55: PATE C_[1]

Pantech Academy of Technical Excellence

Identified by its name. Identified by its signature.

Accessed through a simple name or a member access. Accessed through an element access.

Can be a static or an instance member. Must be an instance member.

A get accessor of a property has no parameters A get accessor of an indexer has the same

formal parameter list as the indexer.

A set accessor of a property contains the implicit

value parameter.

A set accessor of an indexer has the same

formal parameter list as the indexer, in

addition to the value parameter.

55

Page 56: PATE C_[1]

Pantech Academy of Technical Excellence

Structure

56

Structures and Enumerations

Structures

Example for Structure

Structure Features

Enumeration

Example for Enumeration

Page 57: PATE C_[1]

Pantech Academy of Technical Excellence

A struct type is a value type that is typically used to encapsulate small groups of

related variables, such as the coordinates of a rectangle or the characteristics of an item in an

inventory.

The following example shows a simple struct declaration:

public struct Book

{

public decimal price;

public string title;

public string author;

}

Example:

Output:

4

Inside aMethod

57

class TestStruct { public static void Main() { SimpleStruct st = new SimpleStruct(4); System.Console.WriteLine(st.i); st.aMethod(); }}

struct SimpleStruct { public int i; public SimpleStruct(int j) { i=j; }

public void aMethod() { System.Console.WriteLine("Inside aMethod");

}

}

Page 58: PATE C_[1]

Pantech Academy of Technical Excellence

Notes:

Features of Structures

A structure or struct can contain only fields, methods, Etc.,

In struct we can't initialize the variable whereas in class it can be possible

It must be initialized either through function or using object

Fields can't be given initial values at that time of creation.

struct can't have a constructor.

struct can't support the concept of inheritance

We can derive a structure from an interface

We can't inherit from sealed class

A structure could not inherit from a class, the reverse is also true

You can't declare a struct as sealed, because by default it is sealed

A structure declare as abstract can't be used as a base class, i.e., be used in a

derivation

No destructor for struct

58

Structs can also contain constructors, constants, fields, methods, properties, indexers, operators,

events, and nested types, although if several such members are required, you should consider

making your type a class instead. Structs can implement an interface but they cannot inherit from

another struct. For that reason, struct members cannot be declared as protected.

Page 59: PATE C_[1]

Pantech Academy of Technical Excellence

struct are created on the stack and die when we reach the closing brace

Enumerations

An enumeration (also named enum) is a user-defined integer type. When we declare

an enumeration, we specify a set of acceptable values that instances of that enumeration can

contain. Not only that, but we can give the values user-friendly names. If, somewhere in our

code, we attempt to assign a value that is not in the acceptable set of values to an instance of

that enumeration, the compiler will flag an error.

There are at least three benefits to using enumerations instead of plain integers:

Enumerations make your code easier to maintain by helping to ensure that your

variables are assigned only legitimate, anticipated values.

Enumerations make your code clearer by allowing you to refer to integer values by

descriptive names rather than by obscure “magic” numbers.

Enumerations make your code easier to type, too. When you go to assign a value to an

instance of an enumerated type, the Visual Studio .NET IDE will, through

IntelliSense, pop up a list box of acceptable values in order to save you some

keystrokes and to remind you of what the possible options are.

Example:

We can define an enumeration as follows:

public enum TimeOfDay

{

Morning = 0,

Afternoon = 1,

Evening = 2

}

In this case, we use an integer value to represent each period of the day in the

enumeration. We can now access these values as members of the enumeration. For example,

59

Page 60: PATE C_[1]

Pantech Academy of Technical Excellence

TimeOfDay.Morning will return the value 0. We will typically use this enumeration to pass

an appropriate value into a method, and iterate through the possible values in a switch

statement:

60

class EnumExample

{

public static int Main()

{

WriteGreeting(TimeOfDay.Morning);

return 0;

}

static void WriteGreeting(TimeOfDay timeOfDay)

{

switch(timeOfDay)

{

case TimeOfDay.Morning:

Console.WriteLine(“Good morning!”);

break;

case TimeOfDay.Afternoon:

Console.WriteLine(“Good afternoon!”);

break;

case TimeOfDay.Evening:

Console.WriteLine(“Good evening!”);

break;

default:

Strings

Strings

String Escape Sequences

Substring

Null Strings and Empty Strings

Page 61: PATE C_[1]

Pantech Academy of Technical Excellence

61

Page 62: PATE C_[1]

Pantech Academy of Technical Excellence

Strings

A string is an object of type String whose value is text. Internally, the text is stored as

a readonly collection of Char objects, each of which represents one Unicode character

encoded in UTF-16. There is no null-terminating character at the end of a C# string (unlike C

and C++); therefore a C# string can contain any number of embedded null characters ('\0').

string keyword in C# actually refers to the .NET base class System.String. System.String is a

very powerful and versatile class.

String vs System.String

In C#, the string keyword is an alias for String. Therefore, String and string are

equivalent, and you can use whichever naming convention you prefer. The String class

provides many methods for safely creating, manipulating, and comparing strings. In addition,

the C# language overloads some operators to simplify common string operations.

Declaring and Initializing Strings

// Declare without initializing.

string message1;

// Initialize to null.

string message2 = null;

// Initialize as an empty string.

// Use the Empty constant instead of the literal "".

string message3 = System.String.Empty;

//Initialize with a regular string literal.

string oldPath = "c:\\Program Files\\Microsoft Visual Studio 8.0";

62

Page 63: PATE C_[1]

Pantech Academy of Technical Excellence

Notes:

String objects are immutable: they cannot be changed after they have been created. All of

the String methods and C# operators that appear to modify a string actually return the results

in a new string object. In the following example, when the contents of s1 and s2 are

concatenated to form a single string, the two original strings are unmodified. The += operator

creates a new string that contains the combined contents. That new object is assigned to the

variable s1, and the original object that was assigned to s1 is released for garbage collection

because no other variable holds a reference to it.

Example for String concatenation

63

Do not use the new operator to create a string object except when initializing the string with an array

of chars. Initialize a string with the Empty constant value to create a new String object whose string

is of zero length. The string literal representation of a zero-length string is "". By initializing strings

with the Empty value instead of null, you can reduce the chances of a NullReferenceException

occurring. Use the static IsNullOrEmpty(String) method to verify the value of a string before you try

to access it.

string s1 = "A string is more ";

string s2 = "than the sum of its chars.";

// Concatenate s1 and s2. This actually creates a new

// string object and stores it in s1, releasing the

// reference to the original object.

s1 += s2;

System.Console.WriteLine(s1);

// Output: A string is more than the sum of its chars.

Page 64: PATE C_[1]

Pantech Academy of Technical Excellence

String Escape Sequences

Escape Sequence Character Name

\’ Single Quote

\” Double Quote

\\ Black Slash

\0 Null

\a Alert

\b Backspace

\f Form Feed

\n New Line

\r Carriage Return

\t Horizontal tab

\u Unicode Escape Sequence

\v Vertical tab

Substrings

A substring is any sequence of characters that is contained in a string. Use the

Substring method to create a new string from a part of the original string. You can search for

one or more occurrences of a substring by using the IndexOf method. Use the Replace

method to replace all occurrences of a specified substring with a new string. Like the

Substring method, Replace actually returns a new string and does not modify the original

string.

Example:

64

string s3 = "Visual C# Express";

System.Console.WriteLine(s3.Substring(7, 2));

// Output: "C#"

System.Console.WriteLine(s3.Replace("C#", "Basic"));

// Output: "Visual Basic Express"

// Index values are zero-based

int index = s3.IndexOf("C");

// index = 7

Page 65: PATE C_[1]

Pantech Academy of Technical Excellence

Null Strings and Empty Strings

An empty string is an instance of a System.String object that contains zero characters.

Empty strings are used often in various programming scenarios to represent a blank text field.

You can call methods on empty strings because they are valid System.String objects. Empty

strings are initialized as follows:

string s = String.Empty;

By contrast, a null string does not refer to an instance of a System.String object and

any attempt to call a method on a null string causes a NullReferenceException. However, you

can use null strings in concatenation and comparison operations with other strings.

The following examples illustrate some cases in which a reference to a null string

does and does not cause an exception to be thrown:

65

static void Main()

{

string str = "hello";

string nullStr = null;

string emptyStr = "";

string tempStr = str + nullStr; // tempStr = "hello"

bool b = (emptyStr == nullStr);// b = false;

string newStr = emptyStr + nullStr; // creates a new empty string

int len = nullStr.Length; // throws NullReferenceException

Page 66: PATE C_[1]

Pantech Academy of Technical Excellence

66

Collections

Collections

Creating and Manipulating Collections

Collection Classes Overview

Specialized Collections

Page 67: PATE C_[1]

Pantech Academy of Technical Excellence

Collections

A collection is a set of similarly typed objects that are grouped together. Objects of

any type can be grouped into a single collection of the type Object to take advantage of

constructs that are inherent in the language. For example, the C# foreach statement (for each

in Visual Basic) expects all objects in the collection to be of a single type. However, in a

collection of type Object, additional processing is done on the elements individually, such as

boxing and unboxing or conversions, which affect the performance of the collection. Boxing

and unboxing typically occur if storing or retrieving a value type in a collection of type

Object.

Creating and Manipulating Collections

The most common collections are provided by the .NET Framework. You can use any

of them or create your own collection based on one of them. Each collection is designed for

specific purposes. The members included in each System.Collections class reflect the purpose

of the collection. In addition, the generic collections in System.Collections.Generic make it

easy to create strongly typed collections.

If you decide to implement your own collection, use the following guidelines:

Start with the right base class and interfaces.

Consider making your collection strongly typed. Strongly typed collections provide

automatic type validation and avoid processes that adversely affect performance, such

as boxing and unboxing and conversions. If your language supports generics, use one

of the System.Collections.Generic types. If your language does not support generics,

System.Collections.Specialized contains examples of strongly typed collections.

Consider providing synchronization in your class.

Consider enabling serialization for your class.

67

Page 68: PATE C_[1]

Pantech Academy of Technical Excellence

Collection Classes Overview

Collection Classes have the following properties:

Collection classes are defined as part of the System.Collections or

System.Collections.Generic namespace.

Most collection classes derive from the interfaces ICollection, IComparer,

IEnumerable, IList, IDictionary, and IDictionaryEnumerator and their generic

equivalents.

Using generic collection classes provides increased type-safety and in some cases can

provide better performance, especially when storing value types.

Specialized Collections

Specialized collections are collections with highly specific purposes.

NameValueCollection is based on NameObjectCollectionBase; however,

NameValueCollection accepts multiple values per key, whereas NameObjectCollectionBase

accepts only one value per key.

Some strongly typed collections in the System.Collections.Specialized namespace are

StringCollection and StringDictionary, both of which contain values that are exclusively

strings. The CollectionsUtil class creates instances of case-insensitive collections.

Some collections transform. For example, the HybridDictionary class starts as a

ListDictionary and becomes a Hashtable when it becomes large. The KeyedCollection is a list

but it also creates a lookup dictionary when the number of elements reaches a specified

threshold

68

Page 69: PATE C_[1]

Pantech Academy of Technical Excellence

C# PROGRAMMING BASICS

69

Namespaces

Namespaces

Example for Namespace

Namespace Overview

Page 70: PATE C_[1]

Pantech Academy of Technical Excellence

Namespaces

Namespaces are used in C# programming in two ways. First, the .NET Framework

uses namespaces to organize its many classes, as follows:

System.Console.WriteLine("Hello World!");

System is a namespace and Console is a class in that namespace. The using keyword can be

used so that the complete name is not required, as in the following example:

using System;

Console.WriteLine("Hello");

Console.WriteLine("World!");

Second, declaring your own namespaces can help you control the scope of class and method

names in larger programming projects. Use the namespace keyword to declare a namespace,

as in the following example:

Namespaces Overview:

Namespaces have the following properties:

They organize large code projects.

They are delimited by using the. operator.

The using directive obviates the requirement to specify the name of the namespace

for every class.

70

namespace SampleNamespace{ class SampleClass{ public void SampleMethod( ){ System.Console.WriteLine("SampleMethod inside SampleNamespace"); } }}

Page 71: PATE C_[1]

Pantech Academy of Technical Excellence

The global namespace is the "root" namespace: global::System will always refer

to the .NET Framework namespace System.

71

OOPs Concept

Encapsulation

Inheritance

Polymorphism

Classes and Objects

Constructors

Destructors

Method Overloading

Method Overriding

Early Binding, Late Binding

Abstract Classes

Abstract Methods

Interfaces

Multiple Inheritance

Static Classes

Static Constructors

Object Initializer

Events

Attributes

Statements

Page 72: PATE C_[1]

Pantech Academy of Technical Excellence

Why Object oriented approach?

A major factor in the invention of Object-Oriented approach is to remove some of the

flaws in procedural approach. In OOP, data is treated as a critical element and does not allow

it to flow freely. It bounds data closely to the functions that operate on it and protects it from

accidental modification from outside functions. OOP allows decomposition of a problem into

a number of entities called objects and then builds data and functions around these objects. A

major advantage of OOP is code reusability.

Some important features of Object Oriented programming are as follows:

Emphasis on data rather than procedure

Programs are divided into Objects

Data is hidden and cannot be accessed by external functions

Objects can communicate with each other through functions

New data and functions can be easily added whenever necessary

Follows bottom-up approach

Concepts of OOP

Objects

Classes

Data Abstraction and Encapsulation

Inheritance

Polymorphism

Encapsulation

Encapsulation is the procedure of covering up of data and functions into a single unit

(called class). An encapsulated object is often called an abstract data type. Storing data and

functions in a single unit (class) is encapsulation. Data cannot be accessible to the outside

world and only those functions which are stored in the class can access it.

72

Page 73: PATE C_[1]

Pantech Academy of Technical Excellence

Need For Encapsulation

The need of encapsulation is to protect or prevent the code (data) from accidental

corruption due to the errors. In Object oriented programming data is treated as a critical

element in the program development and data is packed closely to the functions that operate

on it and protects it from accidental modification from outside functions.

Encapsulation provides a way to protect data from accidental corruption. Rather than

defining the data in the form of public, we can declare those fields as private. The Private

data are manipulated indirectly by two ways. The first method is using a pair of conventional

accessor and mutator methods. Another one method is using a named property.

Encapsulation Using Accessors and Mutator’s

Let us see an example of Department class. To manipulate the data in that class (String

departname) we define an accessor (get method) and mutator (set method).

73

using system;public class Department{private string departname;.......

// Accessor.public string GetDepartname(){ return departname;}

// Mutator.public void SetDepartname( string a){departname=a;}}

Page 74: PATE C_[1]

Pantech Academy of Technical Excellence

Inheritance

Inheritance is the process by which objects can acquire the properties of objects of

other class. In OOP, inheritance provides reusability, like, adding additional features to an

existing class without modifying it. This is achieved by deriving a new class from the existing

one. The new class will have combined features of both the classes. The class whose

members are inherited is called the base class, and the class that inherits those members is

called the derived class.

Example

Output

Parent Constructor.

Child Constructor.

I'm a Parent Class.

74

using System;public class ParentClass{    public ParentClass( ){            Console.WriteLine("Parent Constructor.");    }    public void print(){       Console.WriteLine("I'm a Parent Class.");    }}public class ChildClass : ParentClass{    public ChildClass( ){            Console.WriteLine("Child Constructor.");    }    public static void Main( ){        ChildClass child = new ChildClass();        child.print();    }}

Page 75: PATE C_[1]

Pantech Academy of Technical Excellence

Polymorphism

Polymorphism means the ability to take more than one form. An operation may

exhibit different behaviors in different instances. The behavior depends on the data types

used in the operation. Polymorphism is extensively used in implementing Inheritance. It has

two distinct aspects:

At run time objects of a derived class may be treated as objects of a base

class in places such as method parameters and collections or arrays. When

this occurs, the objects declared type is no longer identical to its run-time

type.

Base classes may define and implement virtual methods and derived

classes can override them, which means they provide their own definition

and implementation. At run-time, when client code calls method, the CLR

looks up the run-time type of the object, and invokes that override of the

virtual method. Thus in your source code you can call a method on a base

class and cause a derived class’s version of the method to be executed.

Example:

75

public class Shape{ public int X { get; private set; } public int Y { get; private set; } public int Height { get; set; } public int Width { get; set; }

// Virtual method public virtual void Draw() { Console.WriteLine("Performing base class drawing tasks"); }}

class Circle : Shape{ public override void Draw() { // Code to draw a circle... Console.WriteLine("Drawing a circle"); base.Draw(); }}

Page 76: PATE C_[1]

Pantech Academy of Technical Excellence

76

class Rectangle : Shape{ public override void Draw() { // Code to draw a rectangle... Console.WriteLine("Drawing a rectangle"); base.Draw(); }}class Triangle : Shape{ public override void Draw() { // Code to draw a triangle... Console.WriteLine("Drawing a triangle"); base.Draw(); }}

class Program{ static void Main(string[ ] args) { // Polymorphism at work #1: a Rectangle, Triangle and Circle // can all be used where ever a Shape is expected. No cast is // required because an implicit conversion exists from a derived // class to its base class. System.Collections.Generic.List<Shape> shapes = new System.Collections.Generic.List<Shape>(); shapes.Add(new Rectangle()); shapes.Add(new Triangle()); shapes.Add(new Circle());

// Polymorphism at work #2: the virtual method Draw is // invoked on each of the derived classes, not the base class. foreach (Shape s in shapes) { s.Draw(); }

// Keep the console open in debug mode. Console.WriteLine("Press any key to exit."); Console.ReadKey(); }}

Page 77: PATE C_[1]

Pantech Academy of Technical Excellence

Output

Drawing a rectangle

Performing base class drawing tasks

Drawing a triangle

Performing base class drawing tasks

Drawing a circle

Performing base class drawing tasks

Polymorphism Overview

When a derived class inherits from a base class, it gains all the methods, fields,

properties and events of the base class. The designer of the derived class can choose whether

to

override virtual members in the base class,

inherit the closest base class method without overriding it

define new non-virtual implementation of those members that hide the

base class implementations

A derived class can override a base class member only if the base class member is

declared as virtual or abstract. The derived member must use the override keyword to

explicitly indicate that the method is intended to participate in virtual invocation

Classes and Objects

A class is a construct that enables you to create your own custom types by grouping

together variables of other types, methods and events. It defines the data and behavior of a

type. If the class is not declared as static, client code can use it by creating objects or

instances which are assigned to a variable. The variable remains in memory until all

references to it go out of scope. At that time, the CLR marks it as eligible for garbage

collection. If the class is declared as static, then only one copy exists in memory and client

code can only access it through the class itself, not an instance variable.

77

Page 78: PATE C_[1]

Pantech Academy of Technical Excellence

Classes are declared by using the class keyword, as shown in the following example:

public class Customer

{

//Fields, properties, methods and events go here...

}

The class keyword is preceded by the access level. Because public is used in this case,

anyone can create objects from this class. The name of the class follows the class keyword.

The remainder of the definition is the class body, where the behavior and data are defined.

Fields, properties, methods, and events on a class are collectively referred to as class

members.

Objects

An object is basically a block of memory that has been allocated and configured

according to the blueprint. A program may create many objects of the same class. Objects are

also called instances, and they can be stored in either a named variable or in an array or

collection. Client code is the code that uses these variables to call the methods and access the

public properties of the object.

For Example:

Class classname

{

}

classname obj=new classname( ); // Object Created as obj

Creating Objects

An object is a concrete entity based on a class, and is sometimes referred to as an

instance of a class. A class defines a type of object, but it is not an object itself. Objects can

be created by using the new keyword followed by the name of the class.

78

Page 79: PATE C_[1]

Pantech Academy of Technical Excellence

Customer object1 = new Customer( );

You can create an object reference without creating an object at all. A reference can

be made to refer to an object, either by creating a new object, or by assigning it to an existing

object, such as this:

Customer object3 = new Customer ( );

Customer object4 = object3;

Constructors

Constructors are class methods that are executed when an object of a given type is

created. Constructors have the same name as the class, and usually initialize the data

members of the new object. A constructor is a special member function whose task is to

initialize the objects of it's class. This is the first method that is run when an instance of a

type is created.

A constructor is invoked whenever an object of it's associated class is created. If a

class contains a constructor, then an object created by that class will be initialized

automatically. We pass data to the constructor by enclosing it in the parentheses following

the class name when creating an object. Constructors can never return a value, and can be

overridden to provide custom initialization functionality.

A constructor that takes no parameters is called a default constructor. Default

constructors are invoked whenever an object is instantiated by using the new operator and no

arguments are provided to new.

Constructors that take parameters must be called through a new statement or a base

statement. classes and structs can also define multiple constructors, and neither is required to

define a default constructor.

A constructor can use the base keyword to call the constructor of a base class. The

constructor for the base class is called before the block for the constructor is executed. The

79

Page 80: PATE C_[1]

Pantech Academy of Technical Excellence

base keyword can be used with or without parameters. Any parameters to the constructor can

be used as parameters to base, or as part of an expression. In a derived class, if a base-class

constructor is not called explicitly by using the base keyword, the default constructor, if there

is one, is called implicitly. If a base class does not offer a default constructor, the derived

class must make an explicit call to a base constructor by using base.

A constructor can invoke another constructor in the same object by using the “this

“keyword. Like base, this can be used with or without parameters, and any parameters in the

constructor are available as parameters to this, or as part of an expression.

For Example:

public Employee(int weeklySalary, int numberOfWeeks)

: this(weeklySalary * numberOfWeeks)

{

}

Constructors can be marked as public, private, protected, internal, or protected

internal. These access modifiers define how users of the class can construct the class. A

constructor can be declared static by using the static keyword. Static constructors are called

automatically, immediately before any static fields are accessed, and are generally used to

initialize static class members.

For Example:

80

public class Taxi

{

public bool isInitialized;

public Taxi( )

{

isInitialized = true;

}

}

Page 81: PATE C_[1]

Pantech Academy of Technical Excellence

Destructors

Destructors are used to destruct instances of classes. A destructor, also know as

finalizer, is the last method run by a class. Within a destructor we can place code to clean up

the object after it is used, which might include decrementing counters or releasing resources.

When working with destructors we need to use the overrides keyword with Finalize method

as we will override the Finalize method built into the Object class. We normally use Finalize

method to deallocate resources and inform other objects that the current object is going to be

destroyed.

Destructors overview

Destructors cannot be defined in structs. They are only used with classes.

A class can only have one destructor.

Destructors cannot be inherited or overloaded.

Destructors cannot be called. They are invoked automatically.

A destructor does not take modifiers or have parameters.

For Example:

Notes:

81

class Car{ ~Car( ) // destructor { // cleanup statements... }}

Empty destructors should not be used. When a class contains a destructor, an entry is created in

the Finalize queue. When the destructor is called, the garbage collector is invoked to process the

queue. If the destructor is empty, this just causes a needless loss of performance. Destructors are

also called when the program exits. It is possible to force garbage collection by calling Collect,

but most of the time, this should be avoided because it may create performance issues

Page 82: PATE C_[1]

Pantech Academy of Technical Excellence

Method Overloading

C# allows you to define different versions of a method in class, and the compiler will

automatically select the most appropriate one based on the parameters supplied.

For Example:

public int add(int x, int y)

public int add(int x, int y, int z)

Overload 1 requires two integers - exactly the parameters that we are passing in. The

compiler will generate code that calls this overload.

Overload 2 requires three integers.

Method Overriding

Method overriding in C# is a feature like the virtual function in C++. Method

overriding is a feature that allows you to invoke functions (that have the same signatures) that

belong to different classes in the same hierarchy of inheritance using the base class reference.

C# makes use of two keywords: virtual and overrides to accomplish Method overriding.

82

public class AddingNumbers

{

public int Add(int a, int b)

{

return a+b;

}

public int Add(int a, int b, int c)

{

return a+b+c;

Page 83: PATE C_[1]

Pantech Academy of Technical Excellence

For Example:

Output:

BC::Display

DC::Display

The above program compiles and runs successfully to give the expected desired

output. The function Display( ) of Base class BC is declared as virtual, while the Derived

class's implementation of Display( ) is decorated with the modifier override. Doing so

enables C# to invoke functions like Display( ) based on objects the reference variable refers

to and not the type of reference that is invoking the function. Hence in the above program

when b refers to the object of class BC it invokes Display( ) of BC and then when b refers to

the object of class DC it invokes Display() of class DC.

83

class BC{public virtual void Display(){System.Console.WriteLine(“BC::Display“);}}class DC : BC{public override void Display(){System.Console.WriteLine(“DC::Display“);}}Class Demo{Public static void Main(){ BC b; b = new BC(); b.Display();

b = new DC(); b.Display(); }}

Page 84: PATE C_[1]

Pantech Academy of Technical Excellence

Early Binding

Binding refers the object type definition. In Early Binding, if the object type is

specified when declaring your object. Early binding allows developers to interact with the

object’s properties and methods during coding. Also early binding permits the compiler to

check your code. Errors are caught at compile time. Early binding also results in faster code.

It’s disadvantage is that you cannot create a generic object which may be bound to different

types of objects.

Late Binding

Declare your objects as a generic type are late binding. Binding is determined at

object declaration and not at object instantiation. Late binding on the other hand permits

defining generic objects which may be bound to different objects. You could then query the

Controls collection and determine which control you are working on using the TypeOf

method and branch to the section of your code that provides for that type. This is the only

benefit of late binding. Late binding can only be used to access type members that are

declared as Public. And its disadvantage is accessing members declared as Friend or

Protected Friend results in a runtime error.

Abstract Classes

Classes can be declared as abstract. This is accomplished by putting the keyword

abstract before the keyword class in the class definition.

For example:

84

public abstract class A

{

// Class members here.

}

Page 85: PATE C_[1]

Pantech Academy of Technical Excellence

An abstract class cannot be instantiated. The purpose of an abstract class is to provide

a common definition of a base class that multiple derived classes can share. For example, a

class library may define an abstract class that is used as a parameter to many of its functions,

and require programmers using that library to provide their own implementation of the class

by creating a derived class.

Abstract classes may also define abstract methods. This is accomplished by adding

the keyword abstract before the return type of the method.

Abstract Methods

An abstract class can contain abstract and non-abstract methods. When a class inherits

from an abstract, the derived class must implement all the abstract methods declared in the

base class.

An abstract method is a method without any method body. They are implicitly virtual.

But by declaring the derived class also abstract, we can avoid the implementation of all or

certain abstract methods. This is what is known as partial implementation of an abstract class.

Abstract methods have no implementation, so the method definition is followed by a

semicolon instead of a normal method block.

Derived classes of the abstract class must implement all abstract methods. When an

abstract class inherits a virtual method from a base class, the abstract class can override the

virtual method with an abstract method.

For Example:

85

public abstract class A

{

public abstract void DoWork(int i);

}

Page 86: PATE C_[1]

Pantech Academy of Technical Excellence

If a virtual method is declared abstract, it is still virtual to any class inheriting from

the abstract class. A class inheriting an abstract method cannot access the original

implementation of the method. An abstract class can force derived classes to provide new

method implementations for virtual methods.

Interfaces

Interfaces are defined using the interface keyword. An interface looks like a class, but

has no implementation. The only things it contains are definitions of events, indexers,

methods and/or properties. The reason interfaces only provide definitions is because they are

inherited by classes and structs, which must provide an implementation for each interface

member defined.

For Example:

Interfaces describe a group of related behaviors that can belong to any class or struct.

Interfaces can be made up of methods, properties, events, indexers, or any combination of

those four member types. An interface can not contain fields. Interfaces members are

automatically public.

Classes and structs can inherit from interfaces in a manner similar to how classes can

inherit a base class or struct, with two exceptions:

A class or struct can inherit more than one interface.

When a class or struct inherits an interface, it inherits only the method names and

signatures, because the interface itself contains no implementations

86

interface IComparable

{

int CompareTo(object obj);

}

Page 87: PATE C_[1]

Pantech Academy of Technical Excellence

Interfaces Overview:

An interface has the following properties:

An interface is similar to an abstract base class: any non-abstract type inheriting

the interface must implement all its members.

An interface cannot be instantiated directly.

Interfaces can contain events, indexers, methods and properties.

Interfaces contain no implementation of methods.

Classes and structs can inherit from more than one interface.

An interface can itself inherit from multiple interfaces.

Multiple Inheritance

Static Classes

A class can be declared static, indicating that it contains only static members. It is not

possible to create instances of a static class using the new keyword. Static classes are loaded

automatically by the .NET Framework common language runtime (CLR) when the program

or namespace containing the class is loaded.

Use a static class to contain methods that are not associated with a particular object.

For example, it is a common requirement to create a set of methods that do not act on

instance data and are not associated to a specific object in your code. You could use a static

class to hold those methods.

The main features of a static class are:

They only contain static members.

They cannot be instantiated.

They cannot contain Instance Constructors.

They are sealed.

87

Page 88: PATE C_[1]

Pantech Academy of Technical Excellence

Creating a static class is therefore much the same as creating a class that contains only

static members and a private constructor. A private constructor prevents the class from being

instantiated.

The advantage of using a static class is that the compiler can check to make sure that

no instance members are accidentally added. The compiler will guarantee that instances of

this class cannot be created.

Static classes are sealed and therefore cannot be inherited. Static classes cannot

contain a constructor, although it is still possible to declare a static constructor to assign

initial values or set up some static state. Use a static class as a unit of organization for

methods not associated with particular objects. Also, a static class can make your

implementation simpler and faster because you do not have to create an object in order to call

its methods.

For Example:

Static Constructors

A static constructor is used to initialize any static data, or to perform a particular

action that needs performed once only. It is called automatically before the first instance is

created or any static members are referenced.

88

public static class TemperatureConverter{ public static double CelsiusToFahrenheit(string temperatureCelsius) { }

public static double FahrenheitToCelsius(string temperatureFahrenheit) { }}

Page 89: PATE C_[1]

Pantech Academy of Technical Excellence

Syntax:

class SimpleClass

{

// Static constructor

static SimpleClass()

{

//...

}

}

Static constructors have the following properties:

A static constructor does not take access modifiers or have parameters.

A static constructor is called automatically to initialize the class before the first

instance is created or any static members are referenced.

A static constructor cannot be called directly.

The user has no control on when the static constructor is executed in the program.

A typical use of static constructors is when the class is using a log file and the

constructor is used to write entries to this file.

Static constructors are also useful when creating wrapper classes for unmanaged code,

when the constructor can call the LoadLibrary method.

For Example:

The class Bus has a static constructor and one static member, Drive( ). When Drive( ) is

called, the static constructor is invoked to initialize the class.

89

Page 90: PATE C_[1]

Pantech Academy of Technical Excellence

90

public class Bus{ // Static constructor: static Bus() { System.Console.WriteLine("The static constructor invoked."); }

public static void Drive() { System.Console.WriteLine("The Drive method invoked."); }}

class TestBus{ static void Main() { Bus.Drive(); }}

Page 91: PATE C_[1]

Pantech Academy of Technical Excellence

Output:

The static constructor invoked.

The Drive method invoked.

Object Initializer

Object initializer, assign values to any accessible fields or properties of an object at

creation time without having to explicitly invoke a constructor. The following example shows

how to use an object initializer with a named type.

private class Cat

{

// Auto-implemented properties

public int Age { get; set; }

public string Name { get; set; }

}

static void MethodA()

{

// Object initializer

Cat cat = new Cat { Age = 10, Name = "Sylvester" };

}

It is a compile-time error to use a collection initializer with a nullable struct. You can

use object initializers to initialize type objects in a declarative manner without having to

invoke the type's constructor.

Anonymous types must be declared with an object initializer.The following example

shows how to initialize a single new StudentName type by using an object initializer.

StudentName student = new StudentName

91

Page 92: PATE C_[1]

Pantech Academy of Technical Excellence

{

FirstName = "Craig",

LastName = "Playstead",

ID = 116

};

Events

An event in C# is a way for a class to provide notifications to clients of that class

when some interesting thing happens to an object. The most familiar use for events is in

graphical user interfaces; typically, the classes that represent controls in the interface have

events that are notified when the user does something to the control (for example, click a

button).

Events, however, need not be used only for graphical interfaces. Events provide a

generally useful way for objects to signal state changes that may be useful to clients of that

object. Events are an important building block for creating classes that can be reused in a

large number of different programs.

Events are declared using delegates. If you have not yet studied the Delegates

Tutorial, you should do so before continuing. Recall that a delegate object encapsulates a

method so that it can be called anonymously. An event is a way for a class to allow clients to

give it delegates to methods that should be called when the event occurs. When the event

occurs, the delegate(s) given to it by its clients are invoked.

Declaring an event To declare an event inside a class, first a delegate type for the

event must be declared, if none is already declared.

public delegate void ChangedEventHandler(object sender, EventArgs e);

The delegate type defines the set of arguments that are passed to the method that

handles the event. Multiple events can share the same delegate type, so this step is only

necessary if no suitable delegate type has already been declared.

92

Page 93: PATE C_[1]

Pantech Academy of Technical Excellence

Next, the event itself is declared.

public event ChangedEventHandler Changed;

An event is declared like a field of delegate type, except that the keyword event

precedes the event declaration, following the modifiers. Events usually are declared public,

but any accessibility modifier is allowed.

Invoking an event Once a class has declared an event, it can treat that event just like

a field of the indicated delegate type. The field will either be null, if no client has hooked up a

delegate to the event, or else it refers to a delegate that should be called when the event is

invoked. Thus, invoking an event is generally done by first checking for null and then calling

the event.

if (Changed != null)

Changed(this, e);

Invoking an event can only be done from within the class that declared the event.

Hooking up to an event From outside the class that declared it, an event looks like a field,

but access to that field is very restricted.

This is done with the += and -= operators. To begin receiving event invocations,

client code first creates a delegate of the event type that refers to the method that should be

invoked from the event. Then it composes that delegate onto any other delegates that the

event might be connected to using +=.

// Add "ListChanged" to the Changed event on "List":

List.Changed += new ChangedEventHandler(ListChanged);

When the client code is done receiving event invocations, it removes its delegate from

the event by using operator -=.

\

Detach the event and delete the list:

List.Changed -= new ChangedEventHandler(ListChanged);

93

Page 94: PATE C_[1]

Pantech Academy of Technical Excellence

Events in Interfaces

One other difference between events and fields is that an event can be placed in an

interface while a field cannot. When implementing the interface, the implementing class must

supply a corresponding event in the class that implements the interface.

Events and Inheritance

When creating a general component that can be derived from, what seems to be a

problem sometimes arises with events. Since events can only be invoked from within the

class that declared them, derived classes cannot directly invoke events declared within the

base class. Although this is sometimes what is desired, often it is appropriate to give the

derived class the freedom to invoke the event.

Attributes

C# provides a mechanism for defining declarative tags, called attributes, which you

can place on certain entities in your source code to specify additional information. The

information that attributes contain can be retrieved at run time through reflection. You can

use predefined attributes or you can define your own custom attributes.

Attributes can be placed on most any declaration (though a specific attribute might restrict the

types of declarations on which it is valid). Syntactically, an attribute is specified by placing

the name of the attribute, enclosed in square brackets, in front of the declaration of the entity

to which it applies.

For example, a class with the attribute DllImport is declared like this:

[DllImport] public class MyDllimportClass { ... }

Many attributes have parameters, which can be either positional (unnamed) or named. Any

positional parameters must be specified in a certain order and cannot be omitted; named

parameters are optional and can be specified in any order. Positional parameters are specified

first. More than one attribute can be placed on a declaration, either separately or within the

same set of brackets. Some attributes can be specified more than once for a given entity.

94

Page 95: PATE C_[1]

Pantech Academy of Technical Excellence

Statements

The actions that a program takes are expressed in statements. Common actions

include declaring variables, assigning values, calling methods, looping through collections,

and branching to one or another block of code, depending on a given condition. The order in

which statements are executed in a program is called the flow of control or flow of execution.

The flow of control may vary every time that a program is run, depending on how the

program reacts to input that it receives at run time.

A statement can consist of a single line of code that ends in a semicolon, or a series of

single-line statements in a block. A statement block is enclosed in {} brackets and can

contain nested blocks.

Types of Statements

The following table lists the various types of statements in C# and their associated keywords.

Category C# keywords / notes

Declaration statements A declaration statement introduces a new variable or constant. A

variable declaration can optionally assign a value to the variable. In a

constant declaration, the assignment is required.

Expression statements Expression statements that calculate a value must store the value in a

variable.

Selection statements Selection statements enable you to branch to different sections of

code, depending on one or more specified conditions

Iteration statements Iteration statements enable you to loop through collections like arrays,

or perform the same set of statements repeatedly until a specified

condition is met.

Jump statements Jump statements transfer control to another section of code.

95

Page 96: PATE C_[1]

Pantech Academy of Technical Excellence

Exception handling

statements

Exception handling statements enable you to gracefully recover from

exceptional conditions that occur at run time.

Checked and

unchecked

Checked and unchecked statements enable you to specify whether

numerical operations are allowed to cause an overflow when the result

is stored in a variable that is too small to hold the resulting value.

The fixed statement The fixed statement prevents the garbage collector from relocating a

movable variable.

The lock statement The lock statement enables you to limit access to blocks of code to

only one thread at a time.

Labeled statements You can give a statement a label and then use the goto keyword to

jump to the labeled statement.

The empty statement The empty statement consists of a single semicolon. It does nothing

and can be used in places where a statement is required but no action

needs to be performed.

96

Page 97: PATE C_[1]

Pantech Academy of Technical Excellence

EVENT HANDLING

97

Event Handling

System Defined Exceptions

Custom Exceptions

Try, Catch, Finally

Throwing Exceptions

Page 98: PATE C_[1]

Pantech Academy of Technical Excellence

System Defined Exceptions

The C# language's exception handling features provide a way to deal with any

unexpected or exceptional situations that arise while a program is running. Exception

handling uses the try, catch, and finally keywords to attempt actions that may not succeed, to

handle failures, and to clean up resources afterwards. Exceptions can be generated by the

common language runtime (CLR), by third-party libraries, or by the application code using

the throw keyword.

In this example, a method tests for a division by zero, and catches the error. Without

the exception handling, this program would terminate with a DivideByZeroException was

unhandled error.

int SafeDivision(int x, int y)

{

try

{

return (x / y);

}

catch (System.DivideByZeroException dbz)

{

System.Console.WriteLine("Division by zero attempted!");

return 0;

}

}

Exceptions Overview

Exceptions have the following properties:

When your application encounters an exceptional circumstance, such as a division

by zero or low memory warning, an exception is generated.

Use a try block around the statements that might throw exceptions.

Once an exception occurs within the try block, the flow of control immediately

jumps to an associated exception handler, if one is present.

98

Page 99: PATE C_[1]

Pantech Academy of Technical Excellence

If no exception handler for a given exception is present, the program stops

executing with an error message.

If a catch block defines an exception variable, you can use it to get more

information on the type of exception that occurred.

Actions that may result in an exception are executed with the try keyword.

An exception handler is a block of code that is executed when an exception

occurs. In C#, the catch keyword is used to define an exception handler.

Exceptions can be explicitly generated by a program using the throw keyword.

Exception objects contain detailed information about the error, including the state

of the call stack and a text description of the error.

Code in a finally block is executed even if an exception is thrown, thus allowing a

program to release resources.

Custom Exceptions

Introduction

The implementation of Custom Exception Handling using the existing features of C# .Net.

The Concept

The whole idea of having customized Exception Handling is centered on the fact that

there needs to be a generic approach of catching and throwing Exceptions.

For implementing custom Exception Handling we need to derive the class

CustomException from the system base class ApplicationException. In general, for

customizing Exception Handling the following components are necessary:

1. A custom exception class which would host the exception thrown and can be thrown

as a new exception.

2. A message class that would host all user - friendly Application messages that need to

be displayed.

99

Page 100: PATE C_[1]

Pantech Academy of Technical Excellence

Implementation

The following are the steps that are required to implement custom exception for

creation of the above mentioned components:

Step 1:

Define a project called Enumerators that would contain the definitions of all the Enumerators

as the following:

1. The Severity level determines the criticality of the error.

2. The LogLevel determines whether an entry needs to be made in Log. Based on the log

level chosen, entries can be made either in the Debug Log or System Event Log .

Step 2:

Add another project named CustomException. Add a reference of the Enumerators project.

To the project add the following class deriving from ApplicationException:

100

using System;namespace CustomException{/// <summary>/// Severity level of Exception/// </summary>public enum SeverityLevel {Fatal,Critical,Information}/// <summary>/// Log level of Exception/// </summary>public enum LogLevel {Debug,Event}}

Page 101: PATE C_[1]

Pantech Academy of Technical Excellence

101

using System;namespace CustomException{/// <summary>/// Summary description for CustomException/// </summary>public class CustomException : ApplicationException{// private members // defines the severity level of the Exceptionprivate SeverityLevel severityLevelOfException ;// defines the logLevel of the Exceptionprivate LogLevel logLevelOfException ;// System Exception that is thrown private Exception innerException ;// Custom Message private string customMessage ;/// <summary>/// Public accessor of customMessage/// </summary>public string CustomMessage{get {return this.customMessage; }set {this.customMessage = value; }}/// <summary>/// Standard default Constructor/// </summary>public CustomException( ){ }/// <summary>/// Constructor with parameters /// </summary>/// <param name="severityLevel"></param>/// <param name="logLevel"></param>/// <param name="exception"></param>/// <param name="customMessage"></param> public CustomException( SeverityLevel severityLevel , LogLevel logLevel, Exception exception, string customMessage){this.severityLevelOfException = severityLevel ; this.logLevelOfException = logLevel ; this.innerException = exception ;this.customMessage = customMessage ;}}}

Page 102: PATE C_[1]

Pantech Academy of Technical Excellence

One advantage of creating a custom Exception class is that the

Constructor can be enabled to writing to a Log on instantiation of the CustomException

Object using TraceListeners. The entry to the log would be based on the logLevel. This

would force - write an entry each time the custom Exception is thrown.

Thus we have a customException which could be thrown in the catch - handlers of

system - defined exceptions.

Step 3:

For implementing the CustomMessage component , create an Exception.resx File that would

host the error string and the corresponding message string as key-value pair.

Ex. "Test", "Testing Error"

Step 4:

Add to project a CustomMessage.cs class File. This File would look in the following way:

102

using System.Threading;using System.Resources;using System.Reflection;namespace CustomException{/// <summary>/// Summary description for CustomMessage./// </summary>public class CustomMessage{public CustomMessage(){}public string GetString(string key) {// Create a resource manager to retrieve resources.ResourceManager rm = new ResourceManager("Exceptions", Assembly.GetExecutingAssembly());// Get the culture of the currently executing thread.// The value of ci will determine the culture of// the resources that the resource manager retrieves.CultureInfo ci = Thread.CurrentThread.CurrentCulture;// Retrieve the value of the string resource and return it String str = rm.GetString(key, ci);return str ; }}}

Page 103: PATE C_[1]

Pantech Academy of Technical Excellence

The GetString() of the CustomMessage class is used to retrieve the value string

corresponding to the key passed as parameter from the Exceptions resource File.

Usage

a) Add to existing Solution a Test Windows Applications Project.

b) Add the References to both the CustomException and the Enumerators projects.

c) Write a function which would throw a system exception , encapsulated in a try-catch block

as follows :

d) In the Catch Block , re-throw the Exception as a CustomException

e) On a button_click event handler add the following code :

103

private void Updater( ){try {int i = 0; int j = 8 ;int k= j/i;}catch(Exception ex){ SeverityLevel severityLevel = SeverityLevel.Critical;LogLevel logLevel = LogLevel.Debug; CustomMessage customMessage = new CustomMessage();throw new CustomException.CustomException( severityLevel,logLevel,ex.InnerException,customMessage.GetString("Test"));}}

private void buttonTest_Click(object sender, System.EventArgs e){try{this.Updater();}catch(CustomException.CustomException ce){MessageBox.Show(ce.CustomMessage);}}

Page 104: PATE C_[1]

Pantech Academy of Technical Excellence

Try, Catch, Finally

A common usage of catch and finally together is to obtain and use resources in a try

block, deal with exceptional circumstances in a catch block, and release the resources in the

finally block

The purpose of a try-catch block is to catch and handle an exception generated by

working code. Some exceptions can be handled in a catch block and the problem solved

without the exception being re-thrown; however, more often the only thing you can do is

make sure the appropriate exception is thrown.

For Example:

In this example, IndexOutOfRangeException is not the most appropriate exception:

ArgumentOutOfRangeException makes more sense for the method because the error is

caused by the index argument passed in by the caller.

104

class TestTryCatch{ static int GetInt(int[] array, int index) { try { return array[index]; } catch (System.IndexOutOfRangeException e) // CS0168 { System.Console.WriteLine(e.Message); //set IndexOutOfRangeException to the new exception's InnerException throw new System.ArgumentOutOfRangeException("index parameter is out of range.", e); } }}

Page 105: PATE C_[1]

Pantech Academy of Technical Excellence

Example for Try, Catch, Finally

Sample Output

Executing the try statement.

System.NullReferenceException: Object reference not set to an instance of an object.

at EHClass.Main() Caught exception #1.

Executing finally block.

Throwing Exceptions

The throw statement is used to signal the occurrence of an anomalous situation (exception)

during the program execution. The thrown exception is an object whose class is derived from

System.Exception,

105

// try_catch_finally.csusing System;public class EHClass{ static void Main() { try { Console.WriteLine("Executing the try statement."); throw new NullReferenceException(); } catch (NullReferenceException e) { Console.WriteLine("{0} Caught exception #1.", e); } catch { Console.WriteLine("Caught exception #2."); } finally { Console.WriteLine("Executing finally block."); } }}

Page 106: PATE C_[1]

Pantech Academy of Technical Excellence

For Example:

class MyException : System.Exception {}

// ...

throw new MyException();

Usually the throw statement is used with try-catch or try-finally statements. When an

exception is thrown, the program looks for the catch statement that handles this exception.

You can also rethrow a caught exception using the throw statement.

Example:

This example demonstrates how to throw an exception using the throw statement.

Output

The ArgumentNullException exception occurs.

106

using System;public class ThrowTest { static void Main() { string s = null;

if (s == null) { throw new ArgumentNullException(); }

Console.Write("The string s is null"); // not executed }}

Page 107: PATE C_[1]

Pantech Academy of Technical Excellence

OPERATOR OVERLOADING

107

Operators

Unary Operators

Binary Operators

Page 108: PATE C_[1]

Pantech Academy of Technical Excellence

Operators

An operator is a symbol that operates on one or more arguments to produce a

result.C# provides a large set of operators, which are symbols that specify which operations

to perform in an expression. Operations on integral types such as ==, !=, <, >, <=, >=, binary

+, binary -, ^, &, |, ~, ++, --, and sizeof( ) are generally allowed on enumerations. In addition,

many operators can be overloaded by the user, thus changing their meaning when applied to a

user-defined type.

Unary Operators

The +, -, !, ~, ++, --, and cast operators are called the unary operators.

The unary-expression is:

primary-expression

+   unary-expression

- unary-expression

!   unary-expression

~   unary-expression

pre-increment-expression

pre-decrement-expression

cast-expression

Unary plus Operator

The operand is converted to the parameter type of the selected operator, and the type of the

result is the return type of the operator. The predefined unary plus operators are:

int operator +(int x);

uint operator +(uint x);

long operator +(long x);

ulong operator +(ulong x);

float operator +(float x);

108

Page 109: PATE C_[1]

Pantech Academy of Technical Excellence

double operator +(double x);

decimal operator +(decimal x);

For each of these operators, the result is simply the value of the operand.

Unary minus Operator

For an operation of the form –x, unary operator overload resolution is applied to select a

specific operator implementation. The operand is converted to the parameter type of the

selected operator, and the type of the result is the return type of the operator. The predefined

negation operators are:

Integer negation:

int operator –(int x);

long operator –(long x);

The result is computed by subtracting x from zero. If the value of x is the smallest

representable, value of the operand type (−231 for int or −263 for long), then the mathematical

negation of x is not representable within the operand type. If this occurs within a checked

context, a System.OverflowException is thrown; if it occurs within an unchecked context, the

result is the value of the operand and the overflow is not reported.

If the operand of the negation operator is of type uint, it is converted to type long, and

the type of the result is long. An exception is the rule that permits the int value −2147483648

(−231) to be written as a decimal integer literal.

If the operand of the negation operator is of type ulong, a compile-time error occurs. An

exception is the rule that permits the long value −9223372036854775808 (−263) to be written

as a decimal integer literal.

Floating-point negation:

float operator –(float x);

double operator –(double x);

The result is the value of x with its sign inverted. If x is NaN, the result is also NaN.

109

Page 110: PATE C_[1]

Pantech Academy of Technical Excellence

Decimal negation:

decimal operator –(decimal x);

The result is computed by subtracting x from zero. Decimal negation is equivalent to using

the unary minus operator of type System.Decimal.

Logical negation Operator

For an operation of the form !x, unary operator overload resolution is applied to

select a specific operator implementation. The operand is converted to the parameter type of

the selected operator, and the type of the result is the return type of the operator. Only one

predefined logical negation operator exists:

bool operator !(bool x);

This operator computes the logical negation of the operand: If the operand is true, the

result is false. If the operand is false, the result is true.

Bitwise complement Operator

For an operation of the form ~x, unary operator overload resolution is applied to

select a specific operator implementation. The operand is converted to the parameter type of

the selected operator, and the type of the result is the return type of the operator.

The predefined bitwise complement operators are:

int operator ~(int x);

uint operator ~(uint x);

long operator ~(long x);

ulong operator ~(ulong x);

For each of these operators, the result of the operation is the bitwise complement of

x.Every enumeration type E implicitly provides the following bitwise complement operator:

E operator ~(E x);

110

Page 111: PATE C_[1]

Pantech Academy of Technical Excellence

The result of evaluating ~x, where x is an expression of an enumeration type E with an

underlying type U, is exactly the same as evaluating (E)(~(U)x).

Prefix Increment and Decrement Operators

The operand of a prefix increment or decrement operation must be an expression

classified as a variable, a property access, or an indexer access. The result of the operation is

a value of the same type as the operand.

If the operand of a prefix increment or decrement operation is a property or indexer

access, the property or indexer must have both a get and a set accessor. If this is not the case,

a compile-time error occurs.

Unary operator overload resolution is applied to select a specific operator

implementation. Predefined ++ and -- operators exist for the following types: sbyte, byte,

short, ushort, int, uint, long, ulong, char, float, double, decimal, and any enum type. The

predefined ++ operators return the value produced by adding 1 to the operand, and the

predefined -- operators return the value produced by subtracting 1 from the operand.

The run-time processing of a prefix increment or decrement operation of the form ++x or

--x consists of the following steps:

If x is classified as a variable.

x is evaluated to produce the variable.

The selected operator is invoked with the value of x as its argument.

The value returned by the operator is stored in the location given by the evaluation

of x.

The value returned by the operator becomes the result of the operation.

111

pre-increment-expression:

++   unary-expression

pre-decrement-expression:

--   unary-expression

Page 112: PATE C_[1]

Pantech Academy of Technical Excellence

If x is classified as a property or indexer access:

The instance expression (if x is not static) and the argument list (if x is an indexer

access) associated with x are evaluated, and the results are used in the subsequent

get and set accessor invocations.

The get accessor of x is invoked.

The selected operator is invoked with the value returned by the get accessor as its

argument.

The set accessor of x is invoked with the value returned by the operator as its

value argument.

The value returned by the operator becomes the result of the operation.

The ++ and -- operators also support postfix notation. The result of x++ or x-- is the

value of x before the operation, whereas the result of ++x or --x is the value of x after the

operation. In either case, x itself has the same value after the operation.

An operator ++ or operator -- implementation can be invoked using either postfix or prefix

notation. It is not possible to have separate operator implementations for the two notations.

Cast Expressions

A cast-expression is used to explicitly convert an expression to a given type.

cast-expression:

(   type   )   unary-expression

A cast-expression of the form (T)E, where T is a type and E is a unary-expression,

performs an explicit conversion of the value of E to type T. If no explicit conversion exists

from the type of E to T, a compile-time error occurs. Otherwise, the result is the value

produced by the explicit conversion. The result is always classified as a value, even if E

denotes a variable.

The grammar for a cast-expression leads to certain syntactic ambiguities. For

example, the expression (x)–y could either be interpreted as a cast-expression (a cast of –y to

type x) or as an additive-expression combined with a parenthesized-expression (which

computes the value x – y).

112

Page 113: PATE C_[1]

Pantech Academy of Technical Excellence

To resolve cast-expression ambiguities, the following rule exists: A sequence of one or more

tokens enclosed in parentheses is considered the start of a cast-expression only if at least one

of the following are true:

The sequence of tokens is correct grammar for a type, but not for an expression.

The sequence of tokens is correct grammar for a type, and the token immediately

following the closing parentheses is the token "~", the token "!", the token "(", an

identifier, a literal, or any keyword except as and is.

The term "correct grammar" above means only that the sequence of tokens must

conform to the particular grammatical production. It specifically does not consider the actual

meaning of any constituent identifiers. For example, if x and y are identifiers, then x.y is

correct grammar for a type, even if x.y doesn't actually denote a type.

From the disambiguation rule it follows that, if x and y are identifiers, (x)y, (x)(y),

and (x)(-y) are cast-expressions, but (x)-y is not, even if x identifies a type. However, if x is a

keyword that identifies a predefined type (such as int), then all four forms are cast-

expressions (because such a keyword could not possibly be an expression by itself).

Binary Operators

A binary operator must take two parameters, at least one of which must have the class

or struct type in which the operator is declared. Parameters of the shift operators are further

constrained. A binary operator can return any type.

The signature of a binary operator consists of the operator token (+, -, *, /, %, &, |, ^,

<<, >>, ==, !=, >, <, >=, or <=) and the types of the two formal parameters. The return type

and the names of the formal parameters are not part of a binary operator's signature.

Certain binary operators require pair-wise declaration. For every declaration of either

operator of a pair, there must be a matching declaration of the other operator of the pair. Two

operator declarations match when they have the same return type and the same type for each

parameter. The following operators require pair-wise declaration:

113

Page 114: PATE C_[1]

Pantech Academy of Technical Excellence

operator == and operator !=

operator > and operator <

operator >= and operator <=

Binary operators are those operators that work with two operands. For example, a

common binary expression would be a + b—the addition operator (+) surrounded by two

operands. The binary operators are further subdivided into arithmetic, relational, logical, and

assignment operators.

Arithmetic Operators

Arithmetic expressions are composed of two expressions with an arithmetic operator

between them. This includes all the typical mathematical operators as expected in algebra.

The Multiplication Operators

The multiplication operator (*) evaluates two expressions and returns their product. Here's an

example:

int expr1 = 3;

int expr2 = 7;

int product;

product = expr1 * expr2; // product = 21

The Division Operator

The division operator (/), as its name indicates, performs mathematical division. It

takes a dividend expression and divides it by a divisor expression to produce a quotient.

Example:

int dividend = 45;

int divisor = 5;

int quotient;

quotient = dividend / divisor; // quotient = 9

114

Page 115: PATE C_[1]

Pantech Academy of Technical Excellence

The result been a fractional number, it would have been truncated to produce the integer

result.

The Remainder Operator

The remainder operator (%) returns the remainder of a division operation between a

dividend and divisor. A common use of this operator is to create equations that produce a

remainder that falls within a specified range.

Example:

int dividend = 33;

int divisor = 10;

int remainder;

remainder = dividend % divisor; // remainder = 3

The remainder will always be between 0 and 9.

The Addition Operator

The addition operator (+) performs standard mathematical addition by adding one number to

another.

Example:

int one = 1;

int two;

two = one + one; // two = 2

The Subtraction Operator

The subtraction operator (-) performs standard mathematical subtraction by subtracting the

value of one expression from another.

Example:

decimal debt = 537.50m;

decimal payment = 250.00m;

115

Page 116: PATE C_[1]

Pantech Academy of Technical Excellence

decimal balance;

balance = debt - payment; // balance = 287.50

The Left Shift Operator

To shift the bits of a number to the left, use the left shift operator (<<). The effect of this

operation is that all bits move to the left a specified number of times. High-order bits are lost.

Lower order bits are zero filled. This operator may be used on the int, uint, long, and ulong

data types.

Example:

uint intMax = 4294967295; // 11111111111111111111111111111111b

uint byteMask;

byteMask = intMax << 8; // 11111111111111111111111100000000b

The Right Shift Operator

The right shift operator (>>) shifts the bits of a number to the right. By providing a

number to operate on and the number of digits, every bit shifts to the right by the number of

digits specified. Only use the right shift operator on int, uint, long, and ulong data types. The

uint, ulong, positive int, and positive long types shift zeros from the left. The negative int and

negative long types keep a 1 in the sign bit position and fill the next position to the right with

a 0.

Examples:

uint intMax = 4294967295; // 11111111111111111111111111111111b

uint shortMask;

shortMask = intMax >> 16; // 00000000000000001111111111111111b

int intMax = -1; // 11111111111111111111111111111111b

int shortMask;

shortMask = intMax >> 16; // 10000000000000001111111111111111b

C# doesn't have a right shift with zero extension operator (>>>).

116

Page 117: PATE C_[1]

Pantech Academy of Technical Excellence

Relational Operators

Relational operators are used to make a comparison between two expressions. The

primary difference between relational operators and arithmetic operators is that relational

operators return a bool type rather than a number. Another difference is that arithmetic

operators are applicable to certain C# types whereas relational operators can be used on every

possible C# type, whether built-in or not. Floating-point types are evaluated according to

IEEE 754. The results of a relational expression are either true or false.

The Equal Operator

To see if two expressions are the same, use the equal operator (==). The equal operator works

the same for integral, floating-point, decimal, and enum types. It simply compares the two

expressions and returns a bool result.

Example:

bool bresult;

decimal debit = 1500.00m;

decimal credit = 1395.50m;

bresult = debit == credit; // bresult = false

When comparing floating-point types, +0.0 and -0.0 are considered equal. If either floating-

point number is NaN (not a number), equal returns false.

The Not Equal Operator

The not equal operator (!=) is the opposite of the equal operator for all types, with a slight

variation for floating-point types only. If one of the floating-point numbers is NAN (not a

number), not equal returns true.

There are two forms of not equal applicable to expressions. The first is the normal not

equal operator (!=). The other is a negation of the equal operator !(a==b). Normally, these

two forms always evaluate to the same value. The exception occurs when evaluating floating-

point expressions where one or both expressions evaluate to NaN and the relational operator

117

Page 118: PATE C_[1]

Pantech Academy of Technical Excellence

in the negation of an expression is <, >, <=, or >=. The a > b form evaluates to false, but the !

(a<=b) evaluates to true.

Examples:

bool bresult;

decimal debit = 1500.00m;

decimal credit = 1395.50m;

bresult = debit != credit; // bresult = true

bresult = !(debit == credit); // bresult = true

The Less Than Operator

If it's necessary to find out if one value is smaller than another, use the less than

operator (<). The expression on the left is being evaluated and the expression on the right is

the basis of comparison. When the expression on the left is a lower value than the expression

on the right, the result is true. Otherwise, the result is false.

Example:

short redBeads = 2;

short whiteBeads = 23;

bool bresult;

bresult = redBeads < whiteBeads; // bresult=true, work harder

The Greater Than Operator

If it's necessary to know that a certain value is larger than another, use the greater than

operator (>). It compares the expression on the left to the basis expression on the right. When

the expression on the left is a higher value than the expression on the right, the result is true.

Otherwise, the result is false.

118

Page 119: PATE C_[1]

Pantech Academy of Technical Excellence

Example:

short redBeads = 13;

short whiteBeads = 12;

bool bresult;

bresult = redBeads > whiteBeads; // bresult=true, good job!

The Less than or Equal Operator

The expression on the left is compared to the expression on the right. When the

expression on the left is either the same value as or less than the one on the right, less than or

equal returns true. This operator is the opposite of the greater than operator, which means that

!(a>b) would produce the same results. The exception is when there's a floating-point

expression evaluating to NaN, in which case the result is always true.

Example:

float limit = 4.0f;

float currValue = 3.86724f;

bool Bresult;

bresult = currValue <= limit; // bresult = true

The Greater than or Equal Operator

The greater than or equal operator (>=) checks a value to see if it's greater than or

equal to another. When the expression to the left of the operator is the same as or more than

the expression on the right, greater than or equal returns true. The greater than or equal

operator is the opposite of the less than operator.

Example:

double rightAngle = 90.0d;

double myAngle = 96.0d;

bool isAbtuse;

isAbtuse = myAngle >= rightAngle; // Yes, myAngle is abtuse

119

Page 120: PATE C_[1]

Pantech Academy of Technical Excellence

Logical Operators

Logical operators perform Boolean logic on two expressions.There are three types of

logical operators in C#:

Bitwise

Boolean

Conditional.

The bitwise logical operators perform Boolean logic on corresponding bits of two

integral expressions. Valid integral types are the signed and unsigned int and long types.

They return a compatible integral result with each bit conforming to the Boolean evaluation.

Boolean logical operators perform Boolean logic upon two Boolean expressions. The

expression on the left is evaluated, and then the expression on the right is evaluated. Finally,

the two expressions are evaluated together in the context of the Boolean logical operator

between them. They return a bool result corresponding to the type of operator used.

The conditional logical operators operate much the same way as the Boolean logical

operators with one exception in behavior: Once the first expression is evaluated and found to

satisfy the results of the entire expression, the second expression is not evaluated. This is

efficient because it doesn't make sense to continue evaluating an expression when the result is

already known.

The Bitwise AND Operator

The bitwise AND operator (&) compares corresponding bits of two integrals and

returns a result with corresponding bits set to 1 when both integrals have 1 bits. When either

or both integrals have a 0 bit, the corresponding result bit is 0.

Example:

byte oddMask = 1; // 00000001b

byte someByte = 85; // 01010101b

bool isEven;

isEven = (oddMask & someByte) == 0; //(oddMask & someByte) = 1

120

Page 121: PATE C_[1]

Pantech Academy of Technical Excellence

The Bitwise Inclusive OR Operator

The bitwise inclusive OR operator (|) compares corresponding bits of two integrals and

returns a result with corresponding bits set to 1 if either of the integrals have 1 bits in that

position. When both integrals have a 0 in corresponding positions, the result is zero in that

position.

Example:

byte option1 = 1; // 00000001b

byte option2 = 2; // 00000010b

byte totalOptions;

totalOptions = (byte) (option1 | option2); // 00000011b

The Bitwise Exclusive OR Operator

The bitwise exclusive OR operator (^) compares corresponding bits of two integrals

and returns a result with corresponding bits set to 1 if only one of the integrals has a 1 bit

and the other integral has a 0 bit in that position. When both integral bits are 1 or when

both are 0, the result's corresponding bit is 0.

Example:

byte invertMask = 255; // 11111111b

byte someByte = 240; // 11110000b

byte inverse;

inverse = (byte)(someByte ^ invertMask); //inversion=00001111b

The Boolean AND Operator

The Boolean AND operator (&) evaluates two Boolean expressions and returns true when

both expressions evaluate to true. Otherwise, the result is false. The result of each expression

evaluated must return a bool result.

121

Page 122: PATE C_[1]

Pantech Academy of Technical Excellence

Example:

bool inStock = false;

decimal price = 18.95m;

bool buy;

buy = inStock & (price < 20.00m); // buy

The Boolean Inclusive OR Operator

The Boolean inclusive OR operator (|) evaluates the results of two Boolean expressions

and returns true if either of the expressions returns true. When both expressions are false, the

result of the Boolean inclusive OR evaluation is false. Both expressions evaluated must return

a bool type value.

Example:

int mileage = 2305;

int months = 4;

bool changeOil;

changeOil = mileage > 3000 | months > 3; // changeOil = true

The Boolean Exclusive OR Operator

The Boolean exclusive OR operator (^) evaluates the results of two Boolean expressions

and returns true if only one of the expressions returns true. When both expressions are true or

both expressions are false, the result of the Boolean exclusive OR expression is false. In other

words, the expressions must be different.

Example:

bool availFlag = false;

bool toggle = true;

bool available;

available = availFlag ^ toggle; // available = true

122

Page 123: PATE C_[1]

Pantech Academy of Technical Excellence

The Conditional AND Operator

The conditional AND operator (&&) is similar to the Boolean AND operator in that it

evaluates two expressions and returns true when both expressions are true. It is different

when the first expression evaluates to false. Since both expressions must be true, it's

automatically assumed that if the first expression evaluates to false, the entire expression is

false. Therefore, the conditional AND operator returns false and does not evaluate the second

expression. When the first expression is true, the conditional AND operator goes ahead and

evaluates the second expression.

Example:

bool inStock = false;

decimal price = 18.95m;

bool buy;

buy = inStock && (price < 20.00m); // buy = false

that price < 20 will never be evaluated.

The Conditional OR Operator

The conditional OR operator (||) is similar to the Boolean inclusive OR operator (|) in

that it evaluates two expressions and returns true when either expression is true. The

difference is when the first expression evaluates to true. Since either expression can be true to

prove that the overall expression is true, the operator automatically assumes that the entire

expression is true when it finds the first expression is true. Therefore, the conditional OR

operator returns true without evaluating the second expression. When the first expression is

false, the conditional OR operator goes ahead and evaluates the second expression.

Example:

int mileage = 4305;

int months = 4;

bool changeOil;

changeOil = mileage > 3000 || months > 3; // changeOil = true

that mileage>3000 is true, months>3 will never be evaluvated

123

Page 124: PATE C_[1]

Pantech Academy of Technical Excellence

The Assignment Operator

A compound operator is a combination of the assignment operator and an arithmetic

operator, bitwise logical operator, or Boolean logical operator.

Example:

int total = 7;

total += 3; // total = 10

This is the same as saying: total = total + 3.

Table 3.1 shows a list of the available compound assignment operators.

Table 3.1  Compound Assignment Operators

Operator Function

*= Multiplication

/= Division

%= Remainder

+= Addition

-= Subtraction

<<= Left Shift

>>= Right Shift

&= AND

^= Exclusive OR

|= Inclusive OR

Notes

124

When using conditional AND and conditional OR operators, a program does not depend upon

evaluation of the right-hand side of the expression, because it may not be evaluated. Such side

effects are likely to cause bugs.

Page 125: PATE C_[1]

Pantech Academy of Technical Excellence

GENERIC COLLECTIONS

125

Generic Collections

Introduction

Problem Statement

What are Generics

Applying Generics

Generic Constraints

Generics and Casting

Inheritance and Generics

Generics Methods

Generics Delegates

Generics and Reflection

Generics and the .NET Framework

Conclusion

Page 126: PATE C_[1]

Pantech Academy of Technical Excellence

Introduction

Generics are the most powerful feature of C#. Generics allow you to define type-safe

data structures, without committing to actual data types. In concept, generics are similar to

C++ templates, but different in implementation and capabilities.

Generics Problem Statement

Consider, data structure such as a stack, providing the classic Push( ) and Pop( )

methods. When developing a general-purpose stack, you would like to use it to store

instances of various types. Under C# 1.1, you have to use an Object-based stack, meaning

that the internal data type used in the stack is an amorphous Object, and the stack methods

interact with Objects:

public class Stack

{

object[ ] m_Items;

public void Push(object item)

{...}

public object Pop()

{...}

}

Code block 1 shows the full implementation of the Object-based stack. Because Object is the

canonical .NET base type, you can use the Object-based stack to hold any type of items, such

as integers:

Stack stack = new Stack( );

stack.Push(1);

stack.Push(2);

int number = (int)stack.Pop( );

Code block 1. An Object-based stack

126

public class Stack

{

readonly int m_Size;

int m_StackPointer = 0;

object[ ] m_Items;

Page 127: PATE C_[1]

Pantech Academy of Technical Excellence

127

public Stack( ):this(100)

{}

public Stack(int size)

{

m_Size = size;

m_Items = new object[m_Size];

}

public void Push(object item)

{

if(m_StackPointer >= m_Size)

throw new StackOverflowException( );

m_Items[m_StackPointer] = item;

m_StackPointer++;

}

public object Pop( )

{

m_StackPointer--;

if(m_StackPointer >= 0)

{

return m_Items[m_StackPointer];

}

else

{

m_StackPointer = 0;

throw new InvalidOperationException("Cannot pop an empty stack");

}

}

}

Page 128: PATE C_[1]

Pantech Academy of Technical Excellence

However, there are two problems with Object-based solutions. The first issue is

performance. When using value types, you have to box them in order to push and store them,

and unbox the value types when popping them off the stack. Boxing and unboxing incurs a

significant performance penalty in their own right, but it also increases the pressure on the

managed heap, resulting in more garbage collections, which is not great for performance

either. Even when using reference types instead of value types, there is still a performance

penalty because you have to cast from an Object to the actual type you interact with and incur

the casting cost:

Stack stack = new Stack();

stack.Push("1");

string number = (string)stack.Pop();

The second problem with the Object-based solution is type safety. Because the

compiler lets you cast anything to and from Object, you lose compile-time type safety. For

example, the following code compiles fine, but raises an invalid cast exception at run time:

Stack stack = new Stack();

stack.Push(1);

//This compiles, but is not type safe, and will throw an exception:

string number = (string)stack.Pop();

You can overcome these two problems by providing a type-specific (and hence, type-safe)

performant stack.

Unfortunately, solving the performance and type-safety problems this way introduces

a third, and just as serious problem—productivity impact. Writing type-specific data

structures are tedious, repetitive, and error-prone task. When fixing a defect in the data

structure, you have to fix it not just in one place, but in as many places as there are type-

specific duplicates of what is essentially the same data structure. In addition, there is no way

to foresee the use of unknown or yet-undefined future types, so you have to keep an Object-

based data structure as well.

128

Page 129: PATE C_[1]

Pantech Academy of Technical Excellence

What Are Generics

Generics allow you to define type-safe classes without compromising type safety,

performance, or productivity. You implement the server only once as a generic server, while

at the same time you can declare and use it with any type. To do that, use the < and >

brackets, enclosing a generic type parameter.

Example, Usage Of generic stack:

Code block 2 shows the full implementation of the generic stack. Compare Code block 1 to

Code block 2 and see that it is as if every use of object in Code block 1 is replaced with T in

Code block 2, except that the Stack is defined using the generic type parameter T:

public class Stack<T>

{...}

When using a generic stack, you have to instruct the compiler which type to use instead of the

generic type parameter T, both when declaring the variable and when instantiating it:

Stack<int> stack = new Stack<int>();

The compiler and the runtime do the rest. All the methods (or properties) that accept or return

a T will instead use the specified type, an integer in the example above.

129

public class Stack<T>

{

T[ ] m_Items;

public void Push(T item)

{...}

public T Pop()

{...}

}

Stack<int> stack = new Stack<int>();

stack.Push(1);

stack.Push(2);

int number = stack.Pop();

Page 130: PATE C_[1]

Pantech Academy of Technical Excellence

Code block 2. The generic stack

Note   T is the generic type parameter (or type parameter) while the generic type is the

Stack<T>. The int in Stack<int> is the type argument.

The advantage of this programming model is that the internal algorithms and data

manipulation remain the same while the actual data type can change based on the way the

client uses your server code.

130

public class Stack<T>{ readonly int m_Size; int m_StackPointer = 0; T[] m_Items; public Stack():this(100) {} public Stack(int size) { m_Size = size; m_Items = new T[m_Size]; } public void Push(T item) { if(m_StackPointer >= m_Size) throw new StackOverflowException(); m_Items[m_StackPointer] = item; m_StackPointer++; } public T Pop() { m_StackPointer--; if(m_StackPointer >= 0) { return m_Items[m_StackPointer]; } else { m_StackPointer = 0; throw new InvalidOperationException("Cannot pop an empty stack"); } }}

Page 131: PATE C_[1]

Pantech Academy of Technical Excellence

Generics Benefits

Generics in .NET let you reuse code and the effort you put into implementing it. The

types and internal data can change without causing code bloat, regardless of whether you are

using value or reference types. You can develop, test, and deploy your code once, reuse it

with any type, including future types, all with full compiler support and type safety. Because

the generic code does not force the boxing and unboxing of value types, or the down casting

of reference types, performance is greatly improved. With value types there is typically a 200

percent performance gain, and with reference types you can expect up to a 100 percent

performance gain in accessing the type (of course, the application as a whole may or may not

experience any performance improvements). The source code available with this article

includes a micro-benchmark application, which executes a stack in a tight loop. The

application lets you experiment with value and reference types on an Object-based stack and

a generic stack, as well as changing the number of loop iterations to see the effect generics

have on performance.

Applying Generics

Because of the native support for generics in the IL and the CLR, most CLR-

compliant language can take advantage of generic types. For example, here is some Visual

Basic .NET code that uses the generic stack of Code block 2:

You can use generics in classes and in structs. Here is a useful generic point struct:

public struct Point<T>

{

public T X;

131

Dim stack As Stack(Of Integer)

stack = new Stack(Of Integer)

stack.Push(3)

Dim number As Integer

number = stack.Pop()

Page 132: PATE C_[1]

Pantech Academy of Technical Excellence

public T Y;

}

You can use the generic point for integer coordinates, for example:

Point<int> point;

point.X = 1;

point.Y = 2;

Or for charting coordinates that require floating point precision:

Point<double> point;

point.X = 1.2;

point.Y = 3.4;

Besides the basic generics syntax presented so far, C# 2.0 has some generics-specific

syntax. For example, consider the Pop( ) method of Code block 2. Suppose instead of

throwing an exception when the stack is empty, you would like to return the default value of

the type stored in the stack. If you were using an Object-based stack, you would simply return

null, but a generic stack could be used with value types as well. To address this issue, you can

use the default() operator, which returns the default value of a type.

Here is how you can use default in the implementation of the Pop( ) method:

The default value for reference types is null, and the default value for value types

(such as integers, enum, and structures) is a zero whitewash (filling the structure with zeros).

132

public T Pop()

{

m_StackPointer--;

if(m_StackPointer >= 0)

{

return m_Items[m_StackPointer];

}

else

{

m_StackPointer = 0;

return default(T);

}

}

Page 133: PATE C_[1]

Pantech Academy of Technical Excellence

Consequently, if the stack is constructed with strings, the Pop() methods return null when the

stack is empty, and when the stack is constructed with integers, the Pop() methods return

zero when the stack is empty.

Generic Constraints

With C# generics, the compiler compiles the generic code into IL independent of any

type arguments that the clients will use. As a result, the generic code could try to use

methods, properties, or members of the generic type parameters that are incompatible with

the specific type arguments the client uses. This is unacceptable because it amounts to lack of

type safety.

In C# you need to instruct the compiler which constraints the client-specified types

must obey in order for them to be used instead of the generic type parameters. There are three

types of constraints. A derivation constraint indicates to the compiler that the generic type

parameter derives from a base type such an interface or a particular base class.

A default constructor constraint indicates to the compiler that the generic type

parameter exposes a default public constructor (a public constructor with no parameters). A

reference/value type constraint constrains the generic type parameter to be a reference or a

value type.

A generic type can employ multiple constraints, and you even get IntelliSense

reflecting the constraints when using the generic type parameter, such as suggesting methods

or members from the base type.

It is important to note that although constraints are optional, they are often essential

when developing a generic type. Without them, the compiler takes the more conservative,

type-safe approach and only allows access to Object-level functionality in your generic type

parameters. Constraints are part of the generic type metadata so that the client-side compiler

can take advantage of them as well. The client-side compiler only allows the client developer

to use types that comply with the constraints, thus enforcing type safety.

133

Page 134: PATE C_[1]

Pantech Academy of Technical Excellence

Generics and Casting

The C# compiler only lets you implicitly cast generic type parameters to Object, or to

constraint-specified types, as shown in Code block 5. Such implicit casting is type safe

because any incompatibility is discovered at compile-time.

Code block 5: Implicit casting of generic type parameters

The compiler lets you explicitly cast generic type parameters to any other interface, but not to

a class:

134

interface ISomeInterface

{...}

class BaseClass

{...}

class MyClass<T> where T : BaseClass,ISomeInterface

{

void SomeMethod(T t)

{

ISomeInterface obj1 = t;

BaseClass obj2 = t;

object obj3 = t;

}

}

interface ISomeInterface

{...}

class SomeClass

{...}

class MyClass<T>

{

void SomeMethod(T t)

{

ISomeInterface obj1 = (ISomeInterface)t;//Compiles

SomeClass obj2 = (SomeClass)t; //Does not compile

}

}

Page 135: PATE C_[1]

Pantech Academy of Technical Excellence

However, you can force a cast from a generic type parameter to any other type using a

temporary Object variable:

Needless to say, such explicit casting is dangerous because it may throw an exception

at run time if the type argument used instead of the generic type parameter does not derive

from the type to which you explicitly cast. Instead of risking a casting exception, a better

approach is to use the is and as operators, as shown in Code block 6. The is operator returns

true if the generic type parameter is of the queried type, and as will perform a cast if the types

are compatible, and will return null otherwise. You can use is and as on both generic type

parameters and on generic classes with specific type arguments.

Code block 6.:Using 'is' and 'as' operators on generic type parameters

135

class SomeClass{...}

class MyClass<T> { void SomeMethod(T t) { object temp = t; SomeClass obj = (SomeClass)temp; }}

Page 136: PATE C_[1]

Pantech Academy of Technical Excellence

136

public class MyClass<T>

{

public void SomeMethod(T t)

{

if(t is int)

{...}

if(t is LinkedList<int,string>)

{...}

string str = t as string;

if(str != null)

{...}

LinkedList<int,string> list = t as LinkedList<int,string>;

if(list != null)

{...}

}

}

Page 137: PATE C_[1]

Pantech Academy of Technical Excellence

Inheritance and Generics

When deriving from a generic base class, you must provide a type argument instead

of the base-class's generic type parameter:

public class BaseClass<T>

{...}

public class SubClass : BaseClass<int>

{...}

If the subclass is generic, instead of a concrete type argument, you can use the subclass

generic type parameter as the specified type for the generic base class:

public class SubClass<T> : BaseClass<T>

{...}

When using the subclass generic type parameters, you must repeat any constraints stipulated

at the base class level at the subclass level. For example, derivation constraint:

137

public class BaseClass<T> where T : ISomeInterface

{...}

public class SubClass<T> : BaseClass<T> where T : ISomeInterface

{...}

Or constructor constraint:

public class BaseClass<T> where T : new()

{

public T SomeMethod()

{

return new T();

}

}

public class SubClass<T> : BaseClass<T> where T : new()

{...}

Page 138: PATE C_[1]

Pantech Academy of Technical Excellence

A base class can define virtual methods whose signatures use generic type parameters.

When overriding them, the subclass must provide the corresponding types in the method

signatures:

You can define generic interfaces, generic abstract classes, and even generic abstract

methods. These types behave like any other generic base type:

138

public class BaseClass<T>

{

public virtual T SomeMethod()

{...}

}

public class SubClass: BaseClass<int>

{

public override int SomeMethod()

{...}

}

If the subclass is generic it can also use its own generic type parameters for the override:

public class SubClass<T>: BaseClass<T>

{

public override T SomeMethod()

{...}

}

public interface ISomeInterface<T>

{

T SomeMethod(T t);

}

public abstract class BaseClass<T>

{

public abstract T SomeMethod(T t);

}

public class SubClass<T> : BaseClass<T>

{

public override T SomeMethod(T t)

{...)

}

Page 139: PATE C_[1]

Pantech Academy of Technical Excellence

There is an interesting use for generic abstract methods and generic interfaces. In C#

2.0, it is impossible to use operators such as + or += on generic type parameters. For

example, the following code does not compile because C# 2.0 does not have operator

constraints:

public class Calculator<T>

{

public T Add(T arg1,T arg2)

{

return arg1 + arg2;//Does not compile

}

//Rest of the methods

}

Generic Methods

In C# 2.0, a method can define generic type parameters, specific to its execution

scope:

public class MyClass<T>

{

public void MyMethod<X>(X x)

{...}

}

This is an important capability because it allows you to call the method with a different type

every time, which is very handy for utility classes.

You can define method-specific generic type parameters even if the containing class does not

use generics at all:

public class MyClass

{

public void MyMethod<T>(T t)

{...}

}

139

Page 140: PATE C_[1]

Pantech Academy of Technical Excellence

This ability is for methods only. Properties or indexers can only use generic type parameters

defined at the scope of the class.

When calling a method that defines generic type parameters, you can provide the type to use

at the call site:

MyClass obj = new MyClass();

obj.MyMethod<int>(3);

That said, when the method is invoked the C# compiler is smart enough to infer the correct

type based on the type of parameter passed in, and it allows omitting the type specification

altogether:

MyClass obj = new MyClass();

obj.MyMethod(3);

This ability is called generic type inference. Note that the compiler cannot infer the type

based on the type of the returned value alone:

public class MyClass

{

public T MyMethod<T>()

{}

}

MyClass obj = new MyClass();

int number = obj.MyMethod();//Does not compile

When a method defines its own generic type parameters, it can also define constraints for

these types:

However, you cannot provide method-level constraints for class-level generic type

parameters. All constraints for class-level generic type parameters must be defined at the

class scope.

140

Page 141: PATE C_[1]

Pantech Academy of Technical Excellence

When overriding a virtual method that defines generic type parameters, the subclass method

must redefine the method-specific generic type parameter:

Notes:

Generic Static Method

C# allows you to define static methods that use generic type parameters. However,

when invoking such a static method, you need to provide the concrete type for the containing

class at the call site, such as in this example:

public class MyClass<T>

{

public static T SomeMethod(T t)

{...}

}

int number = MyClass<int>.SomeMethod(3);

Static methods can define method-specific generic type parameters and constraints, similar to

instance methods. When calling such methods, you need to provide the method-specific types

at the call site, either explicitly:

Generic static methods are subjected to all constraints imposed on the generic type parameter

they use at the class level. As with instance method, you can provide constraints for generic

type parameters defined by the static method:

Operators in C# are nothing more than static methods and C# allows you to overload

operators for your generic types. Imagine that the generic LinkedList of Code block 3

141

The method override cannot define new constraints that did not appear at the base method. If

the subclass method calls the base class implementation of the virtual method, it must specify

the type argument to use instead of the generic base method type parameter. You can either

explicitly specify it yourself or rely on type inference if it is available:

Page 142: PATE C_[1]

Pantech Academy of Technical Excellence

provided the + operator for concatenating linked lists. The + operator enables you to write the

following elegant code:

LinkedList<int,string> list1 = new LinkedList<int,string>();

LinkedList<int,string> list2 = new LinkedList<int,string>();

...

LinkedList<int,string> list3 = list1+list2;

Generic Delegates

A delegate defined in a class can take advantage of the generic type parameter of that

class.

For Example:

public class MyClass<T>

{

public delegate void GenericDelegate(T t);

public void SomeMethod(T t)

{...}

}

When specifying a type for the containing class, it affects the delegate as well. C# 2.0

allows you to make a direct assignment of a method reference into a delegate variable. The

compiler is capable of inferring the type of the delegate you assign into, finding if the target

object has a method by the name you specify, and verifying that the method's signature

matches. Then, the compiler creates a new delegate of the inferred argument type (including

the correct type instead of the generic type parameter), and assigns the new delegate into the

inferred delegate.

Like classes, structs, and methods, delegates can define generic type parameters too:

Delegates defined outside the scope of a class can use generic type parameters. In that case,

you have to provide the type arguments for the delegate when declaring and instantiating it:

142

Page 143: PATE C_[1]

Pantech Academy of Technical Excellence

The delegate-level constraints are enforced only on the using side, when declaring a

delegate variable and instantiating a delegate object, similar to any other constraint at the

scope of types or methods.

Generic delegates are especially useful when it comes to events. You can literally

define a limited set of generic delegates, distinguished only by the number of the generic type

parameters they require, and use these delegates for all of your event handling needs.

Obviously, if you need more parameters, you can simply add more generic type parameters,

but I wanted to model GenericEventHandler after the non-generic .NET EventHandler,

defined as:

public void delegate EventHandler(object sender,EventArgs args);

Unlike EventHandler, GenericEventHandler is type safe, as shown in Code block 8

because it accepts only objects of the type MyPublisher as senders, rather than mere Object.

In fact, .NET already defines a generic flavor of EventHandler in the System namespace:

public void delegate EventHandler(object sender,A args) where A : EventArgs;

Generics and Reflection

In .NET 2.0, reflection is extended to support generic type parameters. The type Type

can now represent generic types with specific type arguments (called bounded types), or

unspecified (unbounded) types. As in C# 1.1, you can obtain the Type of any type by using

the typeof operator or by calling the GetType() method that every type supports. Regardless

of the way you choose, both yield the same Type.

For example, in the following code sample, type1 is identical to type2.

LinkedList<int,string> list = new LinkedList<int,string>();

Type type1 = typeof(LinkedList<int,string>);

Type type2 = list.GetType();

Debug.Assert(type1 == type2);

Both typeof and GetType() can operate on generic type parameters:

public class MyClass<T>

143

Page 144: PATE C_[1]

Pantech Academy of Technical Excellence

{

public void SomeMethod(T t)

{

Type type = typeof(T);

Debug.Assert(type == t.GetType());

}

}

In addition, the typeof operator can operate on unbounded generic types.

Type has new methods and properties designed to provide reflection information about the

generic aspect of the type.

The most useful of these new members are the HasGenericArguments property and the

GetGenericArguments ( ) and GetGenericTypeDefinition() methods.

As its name indicates, HasGenericArguments is set to true if the type represented by the

Type object uses generic type parameters. GetGenericArguments() returns an array of

Types corresponding to the type arguments used. GetGenericTypeDefinition() returns a

Type representing the generic form of the underlying type.

Similar to Type, MethodInfo and its base class MethodBase have new members that reflect

generic method information.

you can use MethodInfo (as well as a number of other options) for late binding invocation.

However, the type of the parameters you pass for the late binding must match the bounded

types used instead of the generic type parameters (if any):

Attributes and Generics

When defining an attribute, you can instruct the compiler that the attribute should

target generic type parameters, using the new GenericParameter value of the enum

AttributeTargets:

144

Page 145: PATE C_[1]

Pantech Academy of Technical Excellence

Yet internally, an attribute class can take advantage of generics by using generic types or

define helper generic methods, like any other type. C# 2.0 does not allow you to define

generic attributes.

Generics and the .NET Framework

Here we discuss, how some other areas in .NET besides C# itself are taking advantage

of or interacting with generics.

System.Array and Generics

The System.Array type is extended with many generic static methods. The generic

static methods are designed to automate and streamline common tasks of working with

arrays, such as iterating over the array and performing an action on each element, scanning

the array looking for a value that matches a certain criteria (a predicate), converting and

sorting the array, and so on.

System.Array's static generic methods all work with the following four generic delegates

defined in the System namespace:

public delegate void Action<T>(T t);

public delegate int Comparison<T>(T x, T y);

public delegate U Converter<T, U>(T from);

public delegate bool Predicate<T>(T t);

It initializes an array with all the integers from 1 to 20. Then, using an anonymous

method and the Action<T> delegate, the code traces these numbers using the

Array.ForEach() method. Using a second anonymous method and the Predicate<T>

delegate, the code finds all the prime numbers in the array by calling the Array.FindAll()

method, which returns another array of the same generic type. Finally, the prime numbers are

traced using the same Action<T> delegate and anonymous method. Note the use of type

parameter inference in Code block 12. You can use the static methods without specifying the

type parameters.

145

Page 146: PATE C_[1]

Pantech Academy of Technical Excellence

Similar generic methods are also available on the class List<T> defined in the

System.Collections.Generic namespace. These methods use the same four generic delegates.

In fact, you can take advantage of those delegates in your code too, as shown in the following

section.

The Static Collection Class

While both System.Array and List<T> offer handy utility methods that greatly

simplify working with them, .NET does not offer such support for other collections.

The implementation of Collection is straightforward.

For example, here is the ForEach<T>( ) method:

public static void ForEach<T>(IEnumerator<T> iterator,Action<T> action)

{

/* Some parameter checking here, then: */

while(iterator.MoveNext())

{

action(iterator.Current);

}

}

The Collection static class is used very similar to both Array and List<T>, utilizing the

same generic delegates. You can use Collection with any collection, as long as that collection

supports either IEnumerable or IEnumerator:

Generic Collections

The data structures in System.Collections are all Object-based, and thus inheriting the

two problems described at the beginning of this article, namely, inferior performance and

lack of type safety. .NET 2.0 introduces a set of generic collections in the

System.Collections.Generic namespace. For example, there are generic Stack<T> and a

generic Queue<T> classes. The Dictionary<K,T> data structure is equivalent to the non-

generic HashTable, and there is also a SortedDictionary<K,T> class somewhat like

146

Page 147: PATE C_[1]

Pantech Academy of Technical Excellence

SortedList. The class List<T> is analogous to the non-generic ArrayList. Table 1 maps the

main types of System.Collections.Generic to those of System.Collections.

Table 1. Mapping System.Collections.Generic to System.Collections

System.Collections.Generic System.Collections

Comparer<T> Comparer

Dictionary<K,T> HashTable

LinkedList<T> -

List<T> ArrayList

Queue<T> Queue

SortedDictionary<K,T> SortedList

Stack<T> Stack

ICollection<T> ICollection

IComparable<T> System.IComparable

IDictionary<K,T> IDictionary

IEnumerable<T> IEnumerable

IEnumerator<T> IEnumerator

IList<T> IList

Briefly, IEnumerable<T> provides access to the IEnumerator<T> iterator

interface, used for abstracted iterations over the collection. All the collections implement

IEnumerable<T> on a nested struct, where the generic type parameter T is the type the

collection stores.

Of particular interest is the way the dictionary collections define their iterators. A dictionary

is actually a collection of not one but two types of generic parameter—the key and the value.

System.Collection.Generic provides a generic struct called KeyValuePair<K,V>

147

Page 148: PATE C_[1]

Pantech Academy of Technical Excellence

Defined as:

struct KeyValuePair<K,V>

{

public KeyValuePair(K key,V value);

public K Key(get;set;)

public V Value(get;set;)

}

KeyValuePair<K,V> simply stores a pair of a generic key and a generic value. This

struct is what the dictionary manages as a collection, and what it uses for its implementation

of IEnumerable<T>. The Dictionary class specifies the generic KeyValuePair<K,V>

structure as the item argument for IEnumerable<T> and ICollection<T>:

The key and value type parameters used in KeyValuePair<K,V> are of course the dictionary's

own generic key and value type parameters. You can certainly do the same in your own

generic data structures that use pairs of keys and values.

Serialization and Generics

.NET allows you to have serializable generic types:

When serializing a type, besides the state of the object members, .NET persists

metadata about the object and its type. If the serializable type is generic and it contains

bounded types, the metadata about the generic type contains type information about the

bounded types as well. Consequently, each permutation of a generic type with a specific

argument type is considered a unique type.

Note that IFormatter is object-based. You can compensate by defining a generic

version of IFormatter, the use of the two constraints on the generic type parameter F. While

it is possible to use GenericFormatter<F>.

Generics and Remoting

148

Page 149: PATE C_[1]

Pantech Academy of Technical Excellence

You can define and deploy remote classes that utilize generics, and you can use

programmatic or administrative configuration. Consider the class MyServer<T> that uses

generics and is derived from MarshalByRefObject:

public class MyServer<T> : MarshalByRefObject

{...}

You can only access this class over remoting when the type parameter T is a marshalable

object. This implies that T is either a serializable type or is derived from

MarshalByRefObject. You can enforce that by constraining T to derive from

MarshalByRefObject:

public class MyServer<T> : MarshalByRefObject

where T : MarshalByRefObject

{...}

When using administrative type registration, you need to specify the exact type

arguments to use instead of the generic type parameters. You must name the types in a

language-neutral manner, and provide fully qualified namespaces. For example, suppose the

class MyServer<T> is defined in the namespace RemoteServer in the assembly

ServerAssembly, and you want to use it with integer instead of the generic type parameter T,

in client activated mode. In that case, the required client-side type registration entry in the

configuration file would be:

<client url="...some url goes here...">

<activated type="RemoteServer.MyServer[[System.Int32]],ServerAssembly"/>

</client>

The matching host-side type registration entry in the configuration file is:

<service>

<activated type="RemoteServer.MyServer[[System.Int32]],ServerAssembly"/>

</service>

The double square brackets are used to specify multiple types.

For Example:

LinkedList[[System.Int32],[System.String]]

149

Page 150: PATE C_[1]

Pantech Academy of Technical Excellence

When using programmatic configuration, you configure activation modes and type

registration similar to C# 1.1, except when defining the type of the remote object you have to

provide type arguments instead of the generic type parameters.

What Generics Cannot Do

Under .NET 2.0, you cannot define generic Web services. That is, Web methods that

use generic type parameters. The reason is that none of the Web service standards support

generic services.

You also cannot use generic types on a serviced component. The reason is that

generics do not meet COM visibility requirements, which are required for serviced

components (just like you could not use C++ templates in COM or COM+).

Conclusion

C# generics are an invaluable part of your development arsenal. They improve

performance, type safety and quality, reduce repetitive programming tasks, simplify the

overall programming model, and do so with elegant, readable syntax. While the roots of C#

generics are C++ templates, C# takes generics to a new level by providing compile-time

safety and support. C# utilizes two-phase compilation, metadata, and innovative concepts

such as constraints and generic methods. No doubt future versions of C# will continue to

evolve generics, adding new capabilities and extending generics to other areas of .NET

Framework such as data access or localization.

150

Page 151: PATE C_[1]

Pantech Academy of Technical Excellence

ASSEMBLIES

151

Assemblies

Introduction

Private Assemblies

Shared Assemblies

Single File Assemblies

Multi File Assemblies

Global Assembly Cache

Page 152: PATE C_[1]

Pantech Academy of Technical Excellence

Introduction

An assembly is the logical unit that contains compiled code targeted at the .NET

Framework. An assembly is completely self-describing, and is a logical rather than a physical

unit, which means that it can be stored across more than one file. If an assembly is stored in

more than one file, then there will be one main file that contains the entry point and describes

the other files in the assembly.

Assemblies can be viewed using the command line utility ildasm, the MSIL

disassembler. An assembly can be opened by starting ildasm from the command line, with the

assembly as argument or by selecting the menu File➪Open.

Features of Assemblies

Assemblies are self-describing.

Version dependencies are recorded inside an assembly manifest.

Assemblies can be loaded side-by-side.

Application isolation is ensured using application domains.

Installation can be as easy as copying the files that belong to an assembly.

Private Assemblies

A private assembly is used by only one application while a shared assembly is shared

amongst different applications. By default, when a C# program is compiled, the assembly

produced will be a private assembly. This assembly (DLL/EXE) should be placed in the same

folder as the calling application. With a private assembly it’s not necessary to think about

naming conflicts with other classes or versioning problems because each application has its

own copy of the assembly.

152

Page 153: PATE C_[1]

Pantech Academy of Technical Excellence

Shared Assemblies

The assembly must be unique, and therefore have a unique name called a strong

name. Part of the strong name is a mandatory version number. Shared assemblies will mostly

be used when a vendor, different from that of the application, builds the component, or where

a large application is split into subprojects.

The combination of a file name, a public key, a version number and culture (locale

details) gives an assembly a strong name, which is guaranteed to be unique.

Single File Assemblies

A single-file assembly, which is the simplest type of assembly, contains type

information and implementation, as well as the assembly manifest. You can use command-

line compilers or Visual Studio .NET to create a single-file assembly. By default, the

compiler creates an assembly file with an .exe extension.

To create an assembly with an .exe extension

At the command prompt, type the following command:

<compiler command> <module name>

In this command, compiler command is the compiler command for the language used

in your code module, and module name is the name of the code module to compile

into the assembly.

Creating Library Assemblies

The previously described methods create a single-file assembly from a code module

that must contain a single entry point, such as a Main or WinMain method. The compiler

notifies you if the code module does not contain an entry point. If you do not want the

assembly to have an entry point, create a library assembly.

153

Page 154: PATE C_[1]

Pantech Academy of Technical Excellence

A library assembly is similar to a class library. It contains types that will be

referenced by other assemblies, but it has no entry point to begin execution.

To create a library assembly

At the command prompt, type the following command:

<compiler command> /t:library <module name>

In this command, compiler command is the compiler command for the language used

in your code module, and module name is the name of the code module to compile

into the assembly. You can also use other compiler options, such as the /out: option.

Multi File Assemblies

You can create multifile assemblies using command-line compilers or Visual Studio

2005 with Visual C++. One file in the assembly must contain the assembly manifest. An

assembly that starts an application must also contain an entry point, such as a Main or

WinMain method.

Notes:

There are several reasons you might want to create a multifile assembly:

To combine modules written in different languages. This is the most common

reason for creating a multifile assembly.

154

Multifile assemblies can have only one entry point, even if the assembly has multiple code

modules. If you are creating applications that will be downloaded using the <object> tag with

Microsoft Internet Explorer, it is important that you create multifile assemblies. In this

scenario, you create a file separate from your code modules that contain only the assembly

manifest.

Internet Explorer downloads the assembly manifest first, and then creates worker threads to

download any additional modules or assemblies required. While the file containing the

assembly manifest is being downloaded, Internet Explorer will be unresponsive to user input.

The smaller the file containing the assembly manifest, the less time Internet Explorer will be

unresponsive.

Page 155: PATE C_[1]

Pantech Academy of Technical Excellence

To optimize downloading an application by putting seldom-used types in a

module that is downloaded only when needed.

To combine code modules written by several developers. Although each

developer can compile each code module into an assembly, this can force some

types to be exposed publicly that are not exposed if all modules are put into a

multifile assembly.

Once you create the assembly, you can sign the file that contains the assembly

manifest (and hence the assembly), or you can give the file (and the assembly) a strong name

and put it in the global assembly cache.

Global Assembly Cache

To share an assembly among several applications, you can install it into the global

assembly cache. Each computer where the common language runtime is installed has this

machine-wide code cache. The global assembly cache stores assemblies specifically

designated to be shared by several applications on the computer. An assembly must have a

strong name to be installed in the global assembly cache.

You should share assemblies by installing them into the global assembly cache only

when necessary. Keep assembly dependencies private and locate assemblies in the

application directory unless sharing an assembly is explicitly required. To install assemblies

into the global assembly cache to make them accessible to COM interop or unmanaged code.

There are several reasons why you might want to install an assembly into the global assembly

cache:

Shared location.

Assemblies that should be used by applications can be put in the global

assembly cache. Consider, if all applications should use an assembly located in the

global assembly cache, a version policy statement can be added to the Machine.config

file that redirects references to the assembly.

155

Page 156: PATE C_[1]

Pantech Academy of Technical Excellence

File security.

Administrators often protect the systemroot directory using an Access Control

List (ACL) to control write and execute access. Because the global assembly cache is

installed in the systemroot directory, it inherits that directory's ACL. It is

recommended that only users with Administrator privileges be allowed to delete files

from the global assembly cache.

Side-by-side versioning.

Multiple copies of assemblies with the same name but different version

information can be maintained in the global assembly cache. ]

Additional search location.

The common language runtime checks the global assembly cache for an

assembly that matches the assembly request before probing or using the codebase

information in a configuration file.

Notes:

156

If you place one of the assemblies that make up an application into the global assembly cache,

you can no longer replicate or install the application by using XCOPY to copy the application

directory. In this case, you must also move the assembly into the global assembly cache

Assemblies placed in the global assembly cache must have the same assembly name and file

name.

Page 157: PATE C_[1]

Pantech Academy of Technical Excellence

DELEGATES

157

Delegates

Delegates

Delegates Overview

Function Pointers

Multicast Delegates

Page 158: PATE C_[1]

Pantech Academy of Technical Excellence

Delegates

A delegate is a type that references a method. Once a delegate is assigned a method, it

behaves exactly like that method. The delegate method can be used like any other method,

with parameters and a return value.

For Example:

public delegate int PerformCalculation(int x, int y);

Any method that matches the delegate's signature, which consists of the return type

and parameters, can be assigned to the delegate. This makes is possible to programmatically

change method calls, and also plug new code into existing classes. As long as you know the

delegate's signature, you can assign your own delegated method. This ability to refer to a

method as a parameter makes delegates ideal for defining callback methods.

Delegates Overview

Delegates have the following properties:

Delegates are similar to C++ function pointers, but are type safe.

Delegates allow methods to be passed as parameters.

Delegates can be used to define callback methods.

Delegates can be chained together; for example, multiple methods can be called on a

single event.

Methods don't need to match the delegate signature exactly.

C# version 2.0 introduces the concept of Anonymous Methods, which permit code

blocks to be passed as parameters in place of a separately defined method.

158

Page 159: PATE C_[1]

Pantech Academy of Technical Excellence

Why use delegates?

Delegates make our code more extensible by allowing other developers to substitute

their methods in place of our methods. Suppose you have a collection of business objects that

has a LoadData method. You could create an overloaded version of the LoadData method

that allows a developer to tell the LoadData method to call his/her custom method, via a

delegate, to fetch the data for the collection.

What exactly is a delegate?

Delegates are probably one the areas of C#. A delegate is to make an analogy to

classes and interfaces.

In object oriented programming we create classes that have methods and have

implementation code in those methods. If you simply want to define the methods but not

write the implementation code, you can create an interface that describes the methods but

there is no code or functionality to go along with it.

A delegate is to a method as an interface is to a class. In other words, if a function or method

is considered equivalent to a class (because there is implementation code) then a delegate is

equivalent to an interface. Basically, a delegate is a "function/method interface" in the sense

that the delegate describes the return type and parameters of a function.

Function Pointers

Delegates that provide the functionality of function pointers in C# called Function Pointers.

For Example:

Multicast Delegates

159

typedef int(* FUNC_PTR)(void *,void *);

int Compare(void *a, void *b){….}

int callFunction(void *a, void *b){

FUNC_PTR myfunc=Compare;

For(i=left+1;i<=right;i++)

If(myFunc(v[i],v[left]<0) }

Page 160: PATE C_[1]

Pantech Academy of Technical Excellence

A delegate can have more than one element in its invocation list. MulticastDelegate

is a special class. Compilers and other tools can derive from this class, but you cannot derive

from it explicitly.

A MulticastDelegate has a linked list of delegates, called an invocation list,

consisting of one or more elements. When a multicast delegate is invoked, the delegates in

the invocation list are called synchronously in the order in which they appear. If an error

occurs during execution of the list then an exception is thrown.

For Example:

160

delegate void Del(string s);

class TestClass{ static void Hello(string s) { System.Console.WriteLine(" Hello, {0}!", s); }

static void Goodbye(string s) { System.Console.WriteLine(" Goodbye, {0}!", s); }

static void Main() { Del a, b, c, d;

// Create the delegate object a that references // the method Hello: a = Hello;

// Create the delegate object b that references // the method Goodbye: b = Goodbye;

// The two delegates, a and b, are composed to form c: c = a + b;

// Remove a from the composed delegate, leaving d, // which calls only the method Goodbye: d = c - a; System.Console.WriteLine("Invoking delegate a:"); a("A"); System.Console.WriteLine("Invoking delegate b:"); b("B"); System.Console.WriteLine("Invoking delegate c:"); c("C"); System.Console.WriteLine("Invoking delegate d:"); d("D"); }

}

Page 161: PATE C_[1]

Pantech Academy of Technical Excellence

Output

Invoking delegate a:

Hello, A!

Invoking delegate b:

Goodbye, B!

Invoking delegate c:

Hello, C!

Goodbye, C!

Invoking delegate d:

Goodbye, D!

161

Page 162: PATE C_[1]

Pantech Academy of Technical Excellence

USER CONTROLS AND EVENT HANDLING

162

User Controls and Event Handling

User-Defined Controls

Inherited Controls

Inherited Forms

Event Handling

Page 163: PATE C_[1]

Pantech Academy of Technical Excellence

Overview

Embedding user controls in a Windows form is just like adding a simple button or text

box that are already provided with .NET. These basic controls were written essentially like

you code your own controls. Typically the controls you design are to be used in multiple

forms or to modularize your code. These reasons help reduce the amount of code you have to

type as well as make it easier for you to change your implementation. These reduce code

duplication as well as modularize your code.

Custom controls are a key theme in .NET development. They can help your

programming style by improving encapsulation, simplifying a programming model, and

making user interface more "pluggable" (i.e., making it easier to swap out one control and

replace it with a completely different one without rewriting your form code). Of course,

custom controls can have other benefits, including the ability to transform a generic window

into a state-of-the-art modern interface.

Generally, developers tackle custom control development for one of three reasons:

To create controls that abstract away unimportant details and are tailored for a

specific type of data.

To create controls that provide entirely new functionality, or just combine existing

UI elements in a unique way.

To create controls with a distinct original look, or ones that mimic popular

controls in professional applications that aren't available to the masses.

In .NET, creating a custom control is as easy as creating an ordinary class. You

simply inherit from the best possible ancestor and add the specific features you need. Best of

all, you can create a custom control class as part of an existing project, and then decide later

to place it in a separate assembly that can be shared with other programmers.

163

Page 164: PATE C_[1]

Pantech Academy of Technical Excellence

Types of Custom Controls

There are three or four types of controls:

User controls are the simplest type of control. They inherit from the

System.Windows.Forms.UserControl class, and follow a model of composition.

Usually, user controls combine more than one control in a logical

unit (like a group of text boxes for entering address information).

Inherited controls are generally more powerful and flexible. With an inherited

control, you choose the existing .NET control that is closest to what you

want to provide. Then, you derive a custom class that overrides or adds

properties and methods.

Owner-drawn controls generally use GDI+ drawing routines to generate their interfaces

from scratch. Because of this, they tend to inherit from a base class like

System.Windows.Forms.Control. Owner-drawn controls require the most work and provide

the most customizable user interface.

Extender providers, which aren't necessarily controls at all. These components add features

to other controls on a form, and provide a remarkable way to implement

extensible user interface.

Communication between User Controls and subscribing Applications

Because the basic .NET controls are contained within our user control, events are not

fired for the contained applications. Our user control is treated like any other and must

implement it's own properties (besides those inherited from System.Windows.Forms.Control)

and events.

Publishing and Subscribing Events

164

Page 165: PATE C_[1]

Pantech Academy of Technical Excellence

The Event model in C# finds its roots in the event programming model that is popular

in asynchronous programming. The basic foundation behind this programming model is the

idea of "publisher and subscribers." In this model, you have publishers who will do some

logic and publish an "event." Publishers will then send out their event only to subscribers

who have subscribed to receive the specific event.

In C#, any object can publish a set of events to which other applications can

subscribe. When the publishing class raises an event, all the subscribed applications are

notified. The following figure shows this mechanism.

165

Page 166: PATE C_[1]

Pantech Academy of Technical Excellence

Events and Delegates

The heart of Events in C# is Delegates. When an object generates events, it must send

the event out. The way that events are dispatched is through the use of delegates.

Events are declared in C# as follows:

[attributes] [modifier] event type member-name;

Modifier is any allowable scope modifier.

Type must be a delegate.

Member-name is the Name of the Event with which you will refer to the event

in your code.

The important thing to note here is the delegate type that events should use. The

delegate can be any legal delegate. But there is a convention that you should follow and is

one that Window Forms uses. By Convention, the delegate should accept two parameters:

1. The object that generated the event

2. The parameters for the specific event

An example of an event / delegate is as follows:

public delegate void SubmitClickedHandler(object sender, EventArgs e);

public event SubmitClickedHandler SubmitClicked;

SubmitClickedHandler is the name of the delegate, sender is self explanatory. EventArgs is

defined under the System namespace and is a very plain class. SubmitClicked is the name of

the event, which is published to the Subscriber.

Event Handling in C#

Event handlers are methods in an object that are executed in response to some events

occurring in the application. When a user interacts with a GUI control (e.g., clicking a button

on a form, Mouse click, Keyboard press etc.), one or more methods are executed in response

to the above event. Events can also be generated without user interactions

166

Page 167: PATE C_[1]

Pantech Academy of Technical Excellence

Microsoft Foundation Classes (MFC): These classes are based upon Microsoft Win32 API.

Normally development work is done through visual c++.

Java API: Here majority of the work is done by employing AWT and Swing packages.

Actions are enabled by applying Interfaces. The main difficulty is that you should learn and

remember all methods in the corresponding interfaces failing which you would get compile

time errors.

As compared to the above, Event handling in C# is much more simplified. It is possible to

handle various Mouse and Key related events quickly and in a more efficient manner.

1. Invoke the related event by supplying a custom method or event handler.

Using + = operator as shown here:

2.Click += new EventHandler(OnClick);

3.Apply the event handler as described below. It must be in conformity to a delegate of the

class System.EventHandler:

public delegate void EventHandler(object sender, Event args)

The first argument indicates the object sending the event and the second argument

contains information for the current event. You can use this argument object to handle

functionalities associated with the related event.

Listing-1 below illustrates how to print "Hello C#" inside a Textbox when a Button is

clicked:

167

Page 168: PATE C_[1]

Pantech Academy of Technical Excellence

The above example also shows how to handle Resize event. Try resizing the forms border

and observe the result.

168

using System;

using System.Windows.Forms;

using System.Drawing;

public class Butevent:Form

{

TextBox t1 = new TextBox();

Button b1 = new Button();

public Butevent()

{

this.Text = "Program developed by Anand.N";

t1.Location = new Point(20,30);

b1.Text = "Click here to activate";

b1.Location = new Point(20,55);

b1.Size = new Size(150,20);

// Invoking Method or EventHandler

b1.Click+=new EventHandler(OnClick);

this.Controls.Add(t1);

this.Controls.Add(b1);

// Invoking Method or EventHandler

this.Resize += new EventHandler(OnResize);

}

//Applying EventHandler

public void OnResize(object sender,EventArgs ee)

{

MessageBox.Show("oops! Form Resized");

}

//Applying EventHandler

public void OnClick(object sender,EventArgs e)

{

Page 169: PATE C_[1]

Pantech Academy of Technical Excellence

Handling Mouse Events

You can handle various Mouse actions by using the events specified in the Control

class. Following listing shows how to handle a simple MouseUp Event:

Try out the above example and observe the result. Similarly Click, DoubleClick, MouseEnter,

MouseLeave events can be handled in the similar way.

Using Keyboard Events

Every modern programming language contains all necessary functionalities for

handling Keyboard related events. C# also provides us with three events KeyPress, KeyUp

and KeyDown which you can use to handle Keyboard events.

169

using System;

using System.Windows.Forms;

using System.Drawing;

public class Mousedemo:Form

{

public Mousedemo()

{

this.MouseUp += new MouseEventHandler(OnMouseup);

}

public void OnMouseup(object sender,MouseEventArgs e)

{

this.Text = "Current Position (" +e.X + " , " + e.Y +")";

}

public static void Main()

{

Page 170: PATE C_[1]

Pantech Academy of Technical Excellence

Listing-3 below shows the usage of KeyUp Event.

170

using System;

using System.Windows.Forms;

using System.Drawing;

public class Keydemo:Form

{

public Keydemo()

{

this.KeyUp += new KeyEventHandler(OnKeyPress);

}

public void OnKeyPress(object sender, KeyEventArgs e)

{

MessageBox.Show(e.KeyCode.ToString(), "Your input");

}

public static void Main()

{

Page 171: PATE C_[1]

Pantech Academy of Technical Excellence

FILE HANDLING

171

File Handling

File Stream

Stream Reader

Stream Writer

File Info

Directory Info

Page 172: PATE C_[1]

Pantech Academy of Technical Excellence

Files and Folders

One of the ways of permanent storage of data is through files. A file is a collection of

data stored on a secondary storage device, such as the Hard Disk. Every file has a name

associated with it, such as Essay.txt. The name comprises of two parts the base name (in our

case ‘Essay’) and the extension (txt). The portion before the period (.) is the base name

whereas the one after it is the extension. A file name can also contain multiple periods - Dr.

No.avi. The most significant period is always the last one. So, in this case, the base name of

the file would be Dr. No and the extension avi.

The extension is what determines the type of the file. For example, a document has an

extension of doc while a JPEG Image file has an extension of jpg. The base name is what we

specify to identify that particular file.

Files are contained in folders or directories. A directory itself can contain other files

and folders, thus forming a hierarchy. Files within a folder (directory) need to have unique

names. Files with same base name but different extensions are allowed. So, the file My

File.txt and My File.doc can co-exist in a folder. The full path of the file marks its complete

address on a machine. For instance, if the file Notepad.exe is contained inside the Windows

directory of your C drive, its path would be “C:\Windows\Notepad.exe”. Likewise, if it were

to be contained inside the System32 directory which in turn is present in the Windows

directory, the full path would be “C:\Windows\System32\Notepad.exe”.

Stream

A stream is a sequence of bytes travelling from a source to a destination over a

communication medium. Streams can either be input or output. The input stream is used for

reading while the output stream is used for writing. This stream concept does not just apply to

files.

File Stream Classes

.NET provides a lot of classes for handling files. These are contained in the

System.IO namespace.

172

Page 173: PATE C_[1]

Pantech Academy of Technical Excellence

Listed below are various classes under this namespace.

Class Name Description

FileStream Is used to read from and write to any location within a file.

BinaryReader Is used to read primitive data types in the form of binary data from the stream.

StreamReader Is used to read characters from a byte stream.

StringReader Is used to read data from a string buffer.

BinaryWriter Is used to write primitive data types in the form of binary data to the stream.

StreamWriter Is used to write characters to a byte stream.

StringWriter Is used to write data to a string buffer.

DirectoryInfo Is used to perform operations on directories

FileInfo Is used to perform operations on files.

The FileStream class resides under the System.IO namespace and is derived from the

abstract class Stream. It supports random access through seeking. Before you begin reading

from and writing to a file, an object of the FileStream class needs to initialized. The

parameterized constructor of this class allows create/open files and setting up appropriate file

sharing modes.

Creating a new file

FileStream fs = new FileStream

(

"TestFile.txt",

FileMode.Create,

FileAccess.Write,

FileShare.Read

);

The first parameter to the constructor is the path to the file. In this case the new file will be

created in the working directory of the application. A complete path such as C:\Program

Files\Maxotek\Tutorials\C-Sharp\Lesson14\TestFile.txt can also be used. Backslash being the

escape sequence starter would need to be escaped in the string. The code would look

something like:-

173

Page 174: PATE C_[1]

Pantech Academy of Technical Excellence

FileStream fs = new FileStream

(

"C:\\Program Files\\Maxotek\\Tutorials\\C-Sharp\\Lesson14\\TestFile.txt",

FileMode.Create,

FileAccess.Write,

FileShare.Read

);

Another way of doing this, is to use the @ character before the string. This prevents

any escape sequence character as the backslash itself is taken as a normal character.

FileStream fs = new FileStream

(

@"C:\Program Files\Maxotek\Tutorials\C-Sharp\Lesson14\TestFile.txt",

FileMode.Create,

FileAccess.Write,

FileShare.Read

);

The second parameter to the constructor is the FileMode enumeration. It can have any of the

following values.

File Mode Description

Create Creates a new file or truncates the existing file.

CreateNew Creates a new file. If the file already exists, throws a

System.IO.IOException.

Open Opens an existing file. Throws a System.IO.FileNotFoundException if

the file does not exist.

OpenOrCreate Opens an existing file or creates a new one. The difference between this

mode and the Create mode is that it does not truncate the file.

Append Opens the file and seeks to the end. A new file is created if the file does

not exist

Truncate Opens an existing file and truncates its content so that the file size becomes

zero. Attempting to read in this mode throws an exception.

174

Page 175: PATE C_[1]

Pantech Academy of Technical Excellence

The third parameter is the FileAccess which specifies whether the file is to be opened for

Reading (FileAccess.Read), Writing (FileAccess.Write) or both

(FileAccess.ReadWrite).

The last parameter is FileShare mode which states how the file will be shared.

FileShare Mode Description

Read Allows other handles to read from the file.

Write Allows other handles to write to the file.

Delete Allows subsequent deleting of the file.

Inheritable Makes the file handle inheritable to child processes.

NoneDeclines sharing of file. No other process can open

the file until it is closed.

Writing to the File

We use the StreamWriter class which is inherited from the abstract class TextWriter

to write a series of characters. After opening the file in the appropriate mode (Write or

ReadWrite in this case), a new object of the StreamWriter class is created. The object of the

FileStream class is passed to it, thus associating the stream with the file. After this, the

content can be written to the file by using the Write or the WriteLine method. WriteLine

appends an end of line to the content. These two methods are highly overloaded to enable

almost all built in data types to be directly written.

Once you have done all the writing, make sure you close the file using the Close

method. This ensures all the content is physically written to the file. For performance reasons,

the write operation is buffered and sometimes the content might not be physically written to

the file even after the Write method was called. To force all the buffers to be cleared and all

buffered content to be written to the underlying stream (File in our case), use the Flush

method.

175

Page 176: PATE C_[1]

Pantech Academy of Technical Excellence

FileStream fs = new FileStream

(

"TestFile.txt",

FileMode.Create,

FileAccess.Write,

FileShare.Read

);

StreamWriter sw = new StreamWriter(fs);

sw.Write("Hello World"); 

sw.Close(); // Close the Stream

fs.Close(); // Close the File

Reading from a file

The StreamReader class is used to read a series of characters from a FilStream. This

class is derived from the abstract class TextReader. Before reading, the file must be opened

in the appropriate mode (Read or ReadWrite). To Read the next character or the next set of

characters, use the Read method. This method has two forms. One that does not take any

parameters and reads the next character. It returns the byte value of the character. The other

one takes three parameters:-

An array of characters - The read characters are stored in the variable passed here.

The index of the buffer at which to begin writing

Maximum number of characters to read

The ReadLine method reads a line of characters and returns the result in the form of a string.

FileStream fs = new FileStream

(

"TestFile.txt",

FileMode.Open,

FileAccess.Read,

FileShare.Read

);

 StreamReader sr = new StreamReader(fs);

string str = sr.ReadLine();

176

Page 177: PATE C_[1]

Pantech Academy of Technical Excellence

while (str != null)

{

Console.WriteLine(str);

str = sr.ReadLine();

sr.Close(); // Close the Stream

fs.Close(); // Close the File

The file pointer can be seeked to any position of the file using the BaseStream

property’s Seek method. This method takes two parameters. The first, a byte offset relative to

the Origin (second) parameter. This value can be either positive which moves the pointer

down the file or negative which moves the file pointer upwards. The second parameter

known as the Origin parameter indicates the reference point to obtain the new position. The

permissible values are Begin, Current and End.

The following line of code moves the file pointer to the 5th character from the beginning.

sr.BaseStream.Seek(5, SeekOrigin.Begin);

Moves the pointer to the start.

sr.BaseStream.Seek(0, SeekOrigin.Begin);

Moves the pointer to 5 characters ahead of the current position.

sr.BaseStream.Seek(5, SeekOrigin.Current);

Moves the pointer 5 characters backward from the current position.

sr.BaseStream.Seek(-5, SeekOrigin.Begin);

Moves the pointer to the end.

sr.BaseStream.Seek(0, SeekOrigin.End);

The Peek method is used to read the next character without consuming it, i.e the file pointer

does not move ahead.

177

Page 178: PATE C_[1]

Pantech Academy of Technical Excellence

Implementing Binary READ and WRITE

The StreamReader and StreamWriter classes work with character data. In this mode

everything is written as plain text. To implement binary operations, wherein a number such as

327.68 would be written as a float value consuming four bytes and not just as plain text, we

need to use the BinaryReader and BinaryWriter classes.

They are very similar to their text counterparts except that no Line (ReadLine and

WriteLine) methods are provided. The BinaryReader class also supports data type specific

methods such as ReadInt32, ReadDouble, etc. These allow you to directly read the content

from the file in the appropriate format. If we were to use the StreamReader class, we would

have to convert the string to integer or double format using the Convert.ToInt32 and

Convert.ToDouble methods.]

Writing to File

int MyNumber = 69;

BinaryWriter bw = new BinaryWriter(fs);

bw.Write(MyNumber);

Reading from file

BinaryReader br = new BinaryReader(fs);

int MyNumber = br.ReadInt32();

Implementing the Windows File System

Often we need to browse directories and locate files. Many such operations can be

accomplished by using the two classes - DirectoryInfo and FileInfo. Both of these are derived

from the FileSystemInfo class.

The tables below list some of the commonly used properties and methods corresponding to

both of these classes.

178

Page 179: PATE C_[1]

Pantech Academy of Technical Excellence

Properties of DirectoryInfo Class

Property Description

Attributes Gets or sets attributes associated with the current directory.

CreationTime Gets or sets the Creation time of the directory.

Exists Gets a Boolean value indicating whether the directory exists.

FullName Gets a string containing the full path of the directory.

LastAccessTime Gets the last accessed time of the directory.

Name Gets a string containing the name of the directory.

Methods of DirectoryInfo Class

Method Description

Create Creates a directory.

Delete Deletes a directory.

GetDirectories Returns the directories in the current directory. Supports filtering

and recursive listing.

GetFiles Returns the file in the current directory.

Properties of FileInfo class

Property Description

Attributes Gets or sets the attributes associated with the current file.

CreationTime Gets or sets the CreationTime of the file.

Directory Gets an instance of the directory to which the file belongs to.

Exists Gets a Boolean value indicating whether the file exists.

Extension Gets a string containing the extension of the file.

FullName Gets a string containing the full path to the file.

LastAccessTime Gets the last access time of the file.

LastWriteTime Gets the time of the last wriiten activity on the file.

Length Gets the length of the file in Bytes.

Name Gets the name of the File.

179

Page 180: PATE C_[1]

Pantech Academy of Technical Excellence

Methods of FileInfo class

Method Description

Create Creates a new file.

AppendText Appends a text to the file.

Delete Deletes the file.

Open Opens the file.

OpenRead Opens a file in the read-only mode.

Creating Objects

Creating a DirectoryInfo or FileInfo object is very simple. The constructor takes the path to

the file.

DirectoryInfo di = new DirectoryInfo("C:\\Windows");

FileInfo fi = new FileInfo("C:\\Windows\\Notepad.exe");

Listing All Files in a Directory

The following code snippet lists all the files in the C:\Windows directory.

DirectoryInfo di = new DirectoryInfo("C:\\Windows");

FileInfo[ ] fis = di.GetFiles();

foreach (FileInfo fi in fis)

{ Console.WriteLine(fi.Name); }

180

Page 181: PATE C_[1]

Pantech Academy of Technical Excellence

MULTI THREADING

181

Multi Threading

System, Threading

Thread Synchronization

Critical Sections

Thread Life Cycle

Page 182: PATE C_[1]

Pantech Academy of Technical Excellence

What is a thread?

A thread is nothing more than a process.  On the computer, a thread is a process

moving through time.  The process performs sets of sequential steps, each step executing a

line of code.  Because the steps are sequential, each step takes a given amount of time.   The

time it takes to complete a series of steps is the sum of the time it takes to perform each

programming step.

Problems with Threading

If every process in your program was mutually exclusive - that is, no process depended in any

way upon another, then multiple threading would be very easy and very few problems would

occur.  Each process would run along in its own happy course and not bother the other

processes.  However, when more than one process needs to read or write the memory used by

other processes, problems can occur.   With a multithreaded program, two threads can enter a

piece of code at the same time, and wreak havoc on the results.  The problem with threads is

that you need some way to control one thread accessing a shared piece of memory while

another thread running at the same time is allowed to enter the same code and manipulate the

shared data. 

Thread Safety

In our program we force one thread to wait inside our code block while the other

thread is finishing its business.  This activity, known as thread blocking or synchronizing

threads, allows us to control the timing of simultaneous threads running inside our program. 

In C# we lock on a particular part of memory (usually an instance of an object) and don't

allow any thread to enter code of this object's memory until another thread is done using the

object. 

Thread Synchronization

182

Page 183: PATE C_[1]

Pantech Academy of Technical Excellence

The .NET framework provides a number of classes and data types that you can use to

control the access to shared resources.

You can use the System.Threading.Monitor class to lock a section of code in an object's

method that should not be accessed concurrently by many threads.

System.Threading.WaitHandle objects help you respond to actions taken by other threads,

especially when interoperating with unmanaged code. Wait-based techniques use this class to

perform waits on one or more waitable objects.

The System.Threading.Mutex class allows more complex thread synchronization. It

allows single-threaded access. Thread synchronization refers to the act of shielding against

multithreading issues such as data- races, deadlocks and starvation.

The synchronization event classes like the ManualResetEvent and AutoResetEvent 

(both in System.Threading namespace) allow one thread to notify the other threads of some

event. The common language runtime (CLR) provides three ways to synchronize access to

global fields, specific blocks of method, instance and static methods and fields.

Synchronized code regions (SyncBlock based): You can synchronize either the

entire static/instance methods or a part of them using the Monitor class. There is no

support for synchronized static fields. On instance methods, the current object (this

keyword, in C#) is used for synchronization. On static methods, the class is used for

synchronization.

Classic Manual Synchronization: Use the various synchronization classes (like the

WaitHandle, Mutex, ReaderWriterLock, ManualResetEvent, AutoResetEvent and the

Interlocked) to create your own synchronization mechanisms. You have to manually

synchronize the different fields and methods. The Manual based approach can be used

for interprocess synchronization and offers deadlock free waits for multiple resources.

These are two improvements over the SyncBlock based techniques.

Synchronized contexts: You can also use the SynchronizationAttribute to enable

simple, automatic synchronization for ContextBoundObject objects. You can use this

183

Page 184: PATE C_[1]

Pantech Academy of Technical Excellence

technique to synchronize only the instance fields and methods. All objects in the same

context domain share the same lock.

Monitor Class

The Monitor class (in the System.Threading namespace) is useful in situations where you

want a particular region of code to be used only by a single thread at a given point of time.

All the methods in this class are static so you do not need to instantiate this class. These static

methods provide a mechanism to synchronize access to objects thus protecting them against

data-races or deadlocks. A few of the methods are shown below:  

Enter, TryEnter 

Exit 

Pulse / PulseAll 

Wait

You can synchronize access to a piece of code by locking and unlocking a particular

object. The methods Monitor.Enter, Monitor.TryEnter and Monitor.Exit are used to

lock/unlock an object. Once a lock is obtained on a particular piece of code, no other thread

can obtain a lock on the same region of code.

The methods Pulse, PulseAll and Wait must be invoked from within a synchronized

block of code. For each synchronized object you need to maintain a reference to the thread

that currently holds the lock, a reference to a ready queue and a reference to a waiting queue

(that contains the threads that are waiting for notification of a change in the state of the

locked object).

If two threads call Monitor. Enter simultaneously. However close they might be in

calling the Enter method, one thread would always be the one to call it first, and that thread

gets a chance to lock the object. Since, Monitor. Enter is an atomic operation, the CPU cannot

preempt one thread in favor of another. For better performance, you should delay the process

of acquiring lock on the object and should release the lock as soon as possible. It is advisable

to acquire locks on private or internal objects, locking external objects might result in

184

Page 185: PATE C_[1]

Pantech Academy of Technical Excellence

deadlocks, because unrelated code could choose the same objects to lock on for different

purposes.

If it is a block of code on which you want to acquire a lock, then it is better to place

the set of instructions in a try block and to place the Monitor.Exit in the finally block. If it is

an entire method on which you want to acquire a lock (rather than a few lines of code) then

you can use the class MethodImplAttribute (in System.Runtime.CompilerServices

namespace) specifying the Synchronized value in the constructor of the class. This is an

alternative way of working. Since the lock is applied to the entire method the lock is released

when the method returns. But if you want to release the lock sooner then use the Monitor

class or the C# lock statement instead of this attribute.

The C# lock statement provides the same functionality as that provided by the Enter

and Exit methods. Use lock when you have a section of code that should not be interrupted by

code running on a separate thread.

WaitHandle Class

The WaitHandle class (in the System.Threading namespace) is used as a base class for

all synchronization objects that allow multiple wait operations. This class encapsulates the

Win32 synchronization handles. WaitHandle objects signal the status of one thread to another

thereby notifying other threads that they need exclusive access to a resource. Other threads

must then wait, until the wait handle is no longer in use, to use this resource.

Classes derived from this are:

Mutex 

AutoResetEvent 

ManualResetEvent

These classes define a signaling mechanism to take or release exclusive access to a shared

resource. They have two states, signaled and nonsignaled. A wait handle that is not owned by

any thread is in the signaled state otherwise nonsignaled. Threads that own a wait handle call

the Set method when they no longer need the wait handle. Other threads can thus call Reset

185

Page 186: PATE C_[1]

Pantech Academy of Technical Excellence

(to change the status to nonsignaled) or call any one of the WaitHandle methods (shown

below) to request ownership of a wait handle.

These are:  

WaitOne: accepts a wait handle (as an argument) and causes the calling thread to wait

until the current wait handle signal by calling Set.

WaitAny: accepts an array of wait handles (as an argument) and causes the

calling thread to wait until any one of the specified wait handles signal by calling Set.

WaitAll: accepts an array of wait handles (as an argument) and causes the

calling thread to wait until all specified wait handles signal by calling Set. 

 

These wait methods block a thread (similar to the Join method, on individual threads)

until one or more synchronization objects receive a signal. WaitHandle objects represent the

ability to wait on many objects at once and are operating-system waitable objects that are

useful for synchronizing between managed and unmanaged code. But they are less portable

than Monitor objects. Monitor objects are fully managed and are more efficient in their use of

operating system resources.  

Mutex Class

The Mutex class (in the System.Threading namespace) is another way of achieving

synchronization between threads and across processes. This class provides interprocess

synchronization. It allows a thread to have exclusive access to a shared resource thus

preventing simultaneous access by multiple threads or processes. The name mutex itself

suggests that the ownership of the mutex is mutually exclusive. Once one thread acquires a

mutex the other thread that wants to acquire the mutex is suspended till the first thread

releases it.

The method Mutex.ReleaseMutex must be called to release the mutex. A thread can

request the same mutex in repeated calls to Wait but must call the Mutex.ReleaseMutex the

same number of times to release the ownership of the mutex. If no thread owns a mutex (or

the thread that owns a mutex, terminates normally) then the state of the Mutex object is set to

186

Page 187: PATE C_[1]

Pantech Academy of Technical Excellence

signaled otherwise nonsignaled.  Once the state is set to signaled the next thread waiting in

the queue acquires the mutex. The Mutex class corresponds to the Win32 CreateMutex call.

The creation of a Mutex object is very simple. There are three ways of doing so:  

public .ctor(); - creates a Mutex and sets the ownership to the calling thread.

public .ctor(bool owner); - allows you to decide whether the thread calling the Mutex

needs to be the owner or not.

public .ctor(bool owner string name); - also specifies the name of the Mutex.   

A thread can always get the ownership of the mutex by calling any one of the methods

like WaitHandle.WaitOne or WaitHandle.WaitAny or WaitHandle.WaitAll. If no other

thread currently owns the mutex then the calling thread would be granted ownership and the

method WaitOne will return immediately.

But, if any other thread owns the mutex, then WaitOne will spin infinitely till it gets

access to the mutex. You may specify the time (in milliseconds) on the WaitOne method.

This will prevent the infinite wait on the mutex. You can call Close method on the mutex to

release it. Once a mutex has been created, we can use the GetHandle method to obtain a

handle to the mutex that can be used with the WaitHandle.WaitAny or WaitHandle.WaitAll

methods.

Synchronization Events

Synchronization events are wait handles that are used to notify other threads that

something has occurred or that a resource is available. They have two states: signaled and

nonsignaled. There are two synchronization event classes: AutoResetEvent and the

ManualResetEvent.

AutoResetEvent Class

This class notifies one or more waiting threads that an event has occurred. It

187

Page 188: PATE C_[1]

Pantech Academy of Technical Excellence

automatically changes the status to signaled when a waiting thread is released. Instances of

the AutoResetEvent class can also be set to signaled using Set, but the state will

automatically become nonsignaled by the system as soon as a waiting thread is notified that

the event became signaled. If no threads are waiting to listen to the event, the state remains

signaled. This class cannot be inherited.

ManualResetEvent Class

This class also notifies one or more waiting threads that an event has occurred. The

state of the event can be manually set or reset. The state of a manually reset event remains

signaled until the ManualResetEvent.Reset method sets it to the nonsignaled state and the

state remains nonsignaled until the ManualResetEvent.Set method changes the state back to

signaled. This class cannot be inherited.

Interlocked Class

This class (in the System.Threading namespace) helps to synchronize access to

variables that are shared amongst threads. It thus provides atomic operations for variables that

are shared by multiple threads.

You can increment or decrement a shared variable by calling Interlocked.Increment or

Interlocked.Decrement on the shared variable. The advantage is that the two methods operate

in an  "atomic" manner meaning that the methods take an integer, increment (or decrement) it

and return its new value, all in one step. You can also use this class to set the variables to a

specific value (done with Interlocked.Exchange method) or to check the equality of two

variables, if they are equal, replaces one of the variables with a given value

(Interlocked.CompareExchange method).

ReaderWriterLock class

This class (in the System.Threading namespace) defines a lock that works on the

single- writer/multiple-reader mechanism. Thus it offers read/write-aware synchronization.

Any number of threads can read data concurrently. Data locking is needed only when threads

188

Page 189: PATE C_[1]

Pantech Academy of Technical Excellence

are updating. Reader threads can acquire locks, if and only if, there are no writer threads.  

Writer threads can acquire locks if there are no reader and no writer threads. Hence, once a

writer-lock is requested, no new readers will be accepted until the writer has access. It

supports time-outs, thus preventing deadlocks. It also supports nested reader/writer locks.

The function that supports nested reader locks is

ReaderWriterLock.AcquireReaderLock. This thread blocks if a different thread has the writer

lock. The function that supports nested writer locks is ReaderWriterLock.AcquireWriterLock.

This thread blocks if a different thread has the reader lock. Worse it can deadlock if it

has the reader lock. It is always safe to use the ReaderWriterLock.UpgradeToWriterLock

function. This will upgrade the reader thread to writer. You can also change the writer thread

to a reader. The function that does this is called

ReaderWriterLock.DowngradeFromWriterLock.

You can call ReaderWriterLock.ReleaseLock to release the lock and you can use

ReaderWriterLock.RestoreLock to restore the lock state of the thread to what it was before

calling ReaderWriterLock.ReleaseLock.

Thread States: Life Cycle of a Thread

A thread is said to be in one of several thread states. Two classes critical for

multithreaded applications are Thread and Monitor (System.Threading namespace). This

section also discusses several methods of classes Thread and Monitor that cause state

transitions.

A new thread begins its lifecyle in the Unstarted state. The thread remains in the

Unstarted state until the program calls Thread method Start, which places the thread in the

Started state (sometimes called the Ready or Runnable state) and immediately returns control

to the calling thread. Then the thread that invoked Start, the newly Started thread and any

other threads in the program execute concurrently.

189

Page 190: PATE C_[1]

Pantech Academy of Technical Excellence

Figure: Thread Life Cycle

The highest priority Started thread enters the Running state (i.e., begins executing)

when the operating system assigns a processor to the thread. When a Started thread receives a

processor for the first time and becomes a Running thread, the thread executes its ThreadStart

delegate, which specifies the actions the thread will perform during its lifecyle. When a

program creates a new Thread, the program specifies the Thread's ThreadStart delegate as the

argument to the Thread constructor. The ThreadStart delegate must be a method that returns

void and takes no arguments.

A Running thread enters the Stopped (or Dead) state when its ThreadStart delegate

terminates. Note that a program can force a thread into the Stopped state by calling Thread

method Abort on the appropriate Thread object. Method Abort throws a

ThreadAbortException in the thread, normally causing the thread to terminate. When a thread

is in the Stopped state and there are no references to the thread object, the garbage collector

can remove the thread object from memory.

A thread enters the Blocked state when the thread issues an input/output request. The

operating system blocks the thread from executing until the operating system can complete

190

Page 191: PATE C_[1]

Pantech Academy of Technical Excellence

the I/O for which the thread is waiting. At that point, the thread returns to the Started state, so

it can resume execution. A Blocked thread cannot use a processor even if one is available.

There are three ways in which a Running thread enters the WaitSleepJoin state. If a

thread encounters code that it cannot execute yet (normally because a condition is not

satisfied), the thread can call Monitor method Wait to enter the WaitSleepJoin state. Once in

this state, a thread returns to the Started state when another thread invokes Monitor method

Pulse or PulseAll. Method Pulse moves the next waiting thread back to the Started state.

Method PulseAll moves all waiting threads back to the Started state.

A Running thread can call Thread method Sleep to enter the WaitSleepJoin state for a

period of milliseconds specified as the argument to Sleep. A sleeping thread returns to the

Started state when its designated sleep time expires. Sleeping threads cannot use a processor,

even if one is available.

Any thread that enters the WaitSleepJoin state by calling Monitor method Wait or by

calling Thread method Sleep also leaves the WaitSleepJoin state and returns to the Started

state if the sleeping or waiting Thread's Interrupt method is called by another thread in the

program.

If a thread cannot continue executing (we will call this the dependent thread) unless

another thread terminates, the dependent thread calls the other thread's Join method to "join"

the two threads. When two threads are "joined," the dependent thread leaves the

WaitSleepJoin state when the other thread finishes execution (enters the Stopped state). If a

Running Thread's Suspend method is called, the Running thread enters the Suspended state. A

Suspended thread returns to the Started state when another thread in the program invokes the

Suspended thread's Resume method.

191

Page 192: PATE C_[1]

Pantech Academy of Technical Excellence

WINDOWS SERVICES

192

Windows Services

Service Base Class

Service Process Installer

Service Installer

Creating a Windows Service

Install Util.exe

Page 193: PATE C_[1]

Pantech Academy of Technical Excellence

What is a Windows Service?

Windows Service applications are long-running applications that are ideal for use in

server environments. The applications do not have a user interface or produce any visual

output. Any user messages are typically written to the Windows Event Log. Services can be

automatically started when the computer is booted. They do not require a logged in user in

order to execute and can run under the context of any user including the system. Windows

Services are controlled through the Service Control Manager where they can be stopped,

paused, and started as needed.

Service Base Class

Provides a base class for a service that will exist as part of a service application.

ServiceBase must be derived from when creating a new service class.

Derive from ServiceBase when defining your service class in a service application.

Any useful service overrides the OnStart and OnStop methods. For additional functionality,

you can override OnPause and OnContinue with specific behavior in response to changes in

the service state.

A service is a long-running executable that does not support a user interface, and

which might not run under the logged-on user account. The service can run without any user

being logged on to the computer.

By default, services run under the System account, which is not the same as the

Administrator account. You cannot change the rights of the System account. Alternatively,

you can use a ServiceProcessInstaller to specify a user account under which the service will

run.

An executable can contain more than one service but must contain a separate

ServiceInstaller for each service. The ServiceInstaller instance registers the service with the

system. The installer also associates each service with an event log that you can use to record

service commands. The main() function in the executable defines which services should run.

193

Page 194: PATE C_[1]

Pantech Academy of Technical Excellence

The current working directory of the service is the system directory, not the directory in

which the executable is located.

When you start a service, the system locates the executable and runs the OnStart

method for that service, contained within the executable. However, running the service is not

the same as running the executable. The executable only loads the service. The service is

accessed (for example, started and stopped) through the Service Control Manager.

The executable calls the ServiceBase derived class's constructor the first time you call

Start on the service. The OnStart command-handling method is called immediately after the

constructor executes. The constructor is not executed again after the first time the service has

been loaded, so it is necessary to separate the processing performed by the constructor from

that performed by OnStart. Any resources that can be released by OnStop should be created

in OnStart. Creating resources in the constructor prevents them from being created properly if

the service is started again after OnStop has released the resources.

The Service Control Manager (SCM) provides a way to interact with the service. You

can use the SCM to pass Start, Stop, Pause, Continue, or custom commands into the service.

The SCM uses the values of CanStop and CanPauseAndContinue to determine whether the

service accepts Stop, Pause, or Continue commands. Stop, Pause, and Continue are enabled

in the SCM's context menus only if the corresponding property CanStop or

CanPauseAndContinue is true in the service class. If enabled, the command is passed to the

service, and OnStop, OnPause, or OnContinue is called. If CanStop, CanShutdown, or

CanPauseAndContinue is false, the corresponding command-handling method (such as

OnStop) will not be processed, even if you have implemented the method.

You can use the ServiceController class to do programmatically what the SCM does

using a user interface. You can automate the tasks available in the console. If CanStop,

CanShutdown, or CanPauseAndContinue is true but you have not implemented a

corresponding command-handling method (such as OnStop) the system throws an exception

and ignores the command.

You do not have to implement OnStart, OnStop, or any other method in ServiceBase.

However, the service's behavior is described in OnStart, so at minimum, this member should

194

Page 195: PATE C_[1]

Pantech Academy of Technical Excellence

be overridden. The main() function of the executable registers the service in the executable

with the Service Control Manager by calling the Run method. The ServiceName property of

the ServiceBase object passed to the Run method must match the ServiceName property of

the service installer for that service.

 

ServiceProcessInstaller

Installs an executable containing classes that extend ServiceBase. This class is called

by installation utilities, such as InstallUtil.exe, when installing a service application.

The ServiceProcessInstaller does work common to all services in an executable. It is

used by the installation utility to write registry values associated with services you want to

install.

To install a service, create a project installer class that inherits from Installer, and set

the RunInstallerAttribute on the class to true. Within your project, instantiate one

ServiceProcessInstaller instance per service application, and one ServiceInstaller instance for

each service in the application. Finally, add the ServiceProcessInstaller instance and the

ServiceInstaller instances to your project installer class.

When InstallUtil.exe runs, the utility looks for classes in the service assembly with the

RunInstallerAttribute set to true. Add classes to the service assembly by adding them to the

Installers collection associated with your project installer. If Run Installer Attribute is false,

the install utility ignores the project installer.

For an instance of ServiceProcessInstaller, properties you can modify include

specifying that a service application run under an account other than the logged-on user. You

can specify a particular Username and Password pair under which the service should run, or

you can use Account to specify that the service run under the computer's System account, a

local or network service account, or a user account.

195

Page 196: PATE C_[1]

Pantech Academy of Technical Excellence

Notes:

ServiceInstaller Class

Installs a class that extends ServiceBase to implement a service. This class is called

by the install utility when installing a service application.

The ServiceInstaller does work specific to the service with which it is associated. It is

used by the installation utility to write registry values associated with the service to a subkey

within the HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services registry key.

The service is identified by its ServiceName within this subkey. The subkey also includes the

name of the executable or .dll to which the service belongs.

To install a service, create a project installer class that inherits from the Installer class,

and set the RunInstallerAttribute attribute on the class to true. Within your project, instantiate

one ServiceProcessInstaller instance per service application, and one ServiceInstaller instance

for each service in the application. Finally, add the ServiceProcessInstaller instance and the

ServiceInstaller instances to your project installer class.

196

The computer's System account is not the same as the Administrator account. We do not

call the methods on ServiceInstaller within your code; they are generally called only by the

install utility. The install utility automatically calls the ServiceProcessInstaller.Install and

ServiceInstaller.Install methods during the installation process. It backs out failures, if necessary,

by calling Rollback (or ServiceInstaller.Rollback) on all previously installed components.

An application's install routine maintains information automatically about the components

already installed, using the project installer's Installer.Context. This state information is

continuously updated as the ServiceProcessInstaller instance and each ServiceInstaller instance is

installed by the utility. It is usually unnecessary for your code to modify this state information

explicitly.Instantiating a ServiceProcessInstaller causes the base class constructor,

ComponentInstaller, to be called.

Page 197: PATE C_[1]

Pantech Academy of Technical Excellence

When the install utility is called, it looks for the RunInstallerAttribute attribute. If the

attribute is true, the utility installs all the services that were added to the Installers collection

that were associated with your project installer. If RunInstallerAttribute is false or does not

exist, the install utility ignores the project installer.

Notes:

You can modify other properties on the ServiceInstaller either before or after adding it

to the Installers collection of your project installer. For example, a service's StartType may be

set to start the service automatically at reboot or require a user to start the service manually.

Normally, you will not call the methods on ServiceInstaller within your code; they are

generally called only by the install utility. The install utility automatically calls the

ServiceProcessInstaller.Install and ServiceInstaller.Install methods during the installation

process. It backs out failures, if necessary, by calling Rollback (or ServiceInstaller.Rollback)

on all previously installed components.

The installation utility calls Uninstall to remove the object. An application's install

routine maintains information automatically about the components already installed, using

the project installer's Installer.Context. This state information is continuously updated as the

ServiceProcessInstaller instance, and each ServiceInstaller instance is installed by the utility.

It is usually unnecessary for your code to modify state information explicitly.

When the installation is performed, it automatically creates an EventLogInstaller to

install the event log source associated with the ServiceBase derived class. The Log property

for this source is set by the ServiceInstaller constructor to the computer's Application log.

When you set the ServiceName of the ServiceInstaller (which should be identical to the

ServiceBase.ServiceName of the service), the Source is automatically set to the same value.

197

 It is crucial that the ServiceName be identical to the ServiceBase.ServiceName of the class

you derived from ServiceBase. Normally, the value of the ServiceBase.ServiceName property

for the service is set within the Main() function of the service application's executable. The

Service Control Manager uses the ServiceInstaller.ServiceName property to locate the service

within this executable.

Page 198: PATE C_[1]

Pantech Academy of Technical Excellence

In an installation failure, the source's installation is rolled-back along with previously

installed services.

The Uninstall method tries to stop the service if it is running. Whether this succeeds

or not, Uninstall undoes the changes made by Install. If a new source was created for event

logging, the source is deleted.

Installutil.exe

The Installer tool allows you to install and uninstall server resources by executing the

installer components in a specified assembly. This tool works in conjunction with classes in

the System.Configuration.Install Namespace.

installutil [/uninstall][option [...]]assemblyname ]

[option [...]]assemblyname

Here:

Argument Description

assemblyname The name of the assembly in which to execute the

installer components.

Option Description

/h[elp] Displays command syntax and options for the tool.

/help assemblypath Displays any additional options recognized by

individual installers within the specified assembly.

/? Displays command syntax and options for the tool.

/? assemblypath Displays any additional options recognized by

individual installers within the specified assembly.

/LogFile=[filename] Specifies the name of the log file where install

progress is recorded. The default is

assemblyname.InstallLog.

/AssemblyName assemblyName Specifies the name of an assembly. The assembly

198

Page 199: PATE C_[1]

Pantech Academy of Technical Excellence

[,Version=major.minor.build.revision]

[,Culture=locale]

[,PublicKeyToken=publicKeyToken]]

name must be fully qualified with the version,

culture, and public key token of the assembly. The

fully qualified name must be surrounded by quotes.

For example, "myAssembly, Culture=neutral,

PublicKeyToken=0038abc9deabfle5,

Version=2.0.0.0" is a fully qualified assembly name.

/LogToConsole={true|false} If true, displays output to the console. If false (the

default), suppresses output to the console.

/ShowCallStack Prints the call stack to the log if an exception occurs

at any point during installation.

/u[ninstall] Uninstalls an assembly. Unlike other options, /u

applies to all assemblies regardless of where it

appears on the command line.

Starting with the .NET Framework version 2.0, the 32-bit version of

the common language runtime (CLR) continues to ship with only the 32-bit version of the

Installer tool, but the 64-bit version of the CLR ships with both a 32-bit and a 64-bit version

of the Installer tool.

When using the 64-bit CLR, use the 32-bit Installer tool to install 32-bit assemblies,

and the 64-bit Installer tool to install 64-bit and Microsoft intermediate language assemblies.

Otherwise, both versions of the Installer tool behave the same.

Microsoft .NET Framework applications consist of traditional program files and

associated resources, such as message queues, event logs, and performance counters that

must be created when the application is deployed. You can use an assembly's installer

components to create these resources when your application is installed and to remove them

when your application is uninstalled. Installutil.exe detects and executes these installer

components.

You can specify multiple assemblies on the same command line. Any option that

occurs before an assembly name applies to that assembly's installation. Options specified for

199

Page 200: PATE C_[1]

Pantech Academy of Technical Excellence

one assembly apply to any subsequent assemblies unless the option is specified with a new

assembly name.

Installutil.exe uses reflection to inspect the specified assembly and find all Installer

types with the RunInstallerAttribute set to true. The tool then executes either the Install

Method or the Uninstall Method on each instance of the Installer type. Installutil.exe

performs installation in a transactional manner; if one of the assemblies fails to install, it rolls

back the installations of all other assemblies. Uninstall is not transactional.

Installutil.exe can not install or uninstall delay signed assemblies, but can install or

uninstall strong named assemblies.

Notes

Create a Windows Service

The service we will create does nothing really useful other than serve as a

demonstration. When the service is started we will log an entry in a database indicating that it

has started. The service will create a database entry on a specified interval during the time in

which it is running. The service will create a final database entry when stopping. The service

will also automatically log an entry in the Windows Application Log when it is successfully

started or stopped.\

Visual Studio .NET makes it relatively simple to create a Windows Service. The

instructions for starting our demo service are outlined below.

200

You cannot deploy a Windows service created using C++ with Installutil.exe.

Installutil.exe cannot recognize the embedded native code that is produced by the C++

compiler. If you attempt to deploy a C++ Windows service with Installutil.exe, an exception

such as BadImageFormatException will be thrown. To work with this scenario, move the

service code to a C++ module. Then, write the installer object in C# or Visual Basic.

Page 201: PATE C_[1]

Pantech Academy of Technical Excellence

1. Start a new project

2. Select Windows Service from the list of available project templates

3. The designer will open in design mode

4. Drag a Timer object from the Components tab in the Toolbox onto the design surface

(Warning: make sure you use the Timer from the Components tab and not the one

from the Windows Forms tab)

5. Through the Timer properties set the Enabled property to False and the Interval

property to 30000 milliseconds

6. Switch to the code behind view (F7) to add functionality to the service

Makeup of a Windows Service

In the code behind class you will notice that your Windows Service extends the

System.ServiceProcess.Service class. All Windows Services built in .NET must extend this

class. It requires your service to override the following methods which Visual Studio will

include by default.

Dispose - clean up any managed and unmanaged resources

OnStart - control the service startup

OnStop - control the service stoppage

Sample Database Table Script

The following T-SQL script can be used to create the database table used in the

example. I am using SQL Server as my database of choice. You can easily modify this

example to work with Access or any other database of your choice.

CREATE TABLE [dbo].[MyServiceLog] (

[in_LogId] [int] IDENTITY (1, 1) NOT NULL,

[vc_Status] [nvarchar] (40)

COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,

[dt_Created] [datetime] NOT NULL

) ON [PRIMARY]

201

Page 202: PATE C_[1]

Pantech Academy of Technical Excellence

Install the Windows Service

Windows Services are different than normal Windows based applications. It is not

possible to run a Windows Service by simply running an EXE. The Windows Service should

be installed by using the InstallUtil.exe provided with the .NET Framework or through a

deployment project such as a Microsoft Installer (MSI) file.

Add an Installer

Having created the Windows Service will not be enough for the InstallUtil program to be

able to install the service. You must also add an Installer to your Windows Service so that the

InstallUtil, or any other installation program, knows what configuration settings to apply to

your service.

1. Switch to the design view for the service

2. Right click and select Add Installer

3. Switch to the design view of the ProjectInstaller that is added

4. Set the properties of the serviceInstaller1 component

i. ServiceName = My Sample Service

ii. StartType = Automatic

5. Set the properties of the serviceProcessInstaller1 component

a. Account = LocalSystem

b. Build the Solution

Use InstallUtil to Install the Windows Service

Now that the service has been built you need to install it for use. The following

instructions will guide you in installing your new service.

1. Open a Visual Studio .NET Command Prompt

2. Change to the bin\Debug directory of your project location (bin\Release if you

compiled in release mode)

202

Page 203: PATE C_[1]

Pantech Academy of Technical Excellence

3. Issue the command InstallUtil.exe MyWindowsService.exe to register the service and

have it create the appropriate registry entries

4. Open the Computer Management console by right clicking on My Computer on the

desktop and selecting Manage

5. In the Services section underneath Services and Applications you should now see

your Windows Service included in the list of services

6. Start your service by right clicking on it and selecting Start

Each time you need to change your Windows Service it will require you to uninstall and

reinstall the service. Prior to uninstalling the service it is a good idea to make sure you have

the Services management console closed. If you do not you may have difficulty uninstalling

and reinstalling the Windows Service. To uninstall the service simply reissue the same

InstallUtil command used to register the service and add the /u command switch.

Debug the Windows Service

As with all other aspects, debugging a Windows Service is different than a normal

application. More steps are required to debug a Windows Service. The service cannot be

debugged by simply executing it in the development environment as you can with a normal

application. The service must first be installed and started, which we covered in the previous

section. Once it is started you attach Visual Studio to the running process in order to step

through and debug the code. Remember, each change you make to the Windows Service will

require you to uninstall and reinstall the service.

Attach to a Running Windows Service

Here are the directions for attaching to a Windows Service in order to debug the

application. These instructions assume that you have already installed the Windows Service

and it is currently running.

1. Load the project into Visual Studio

2. Click on the Debug menu

3. Click on the Processes menu item

4. Make sure the Show system processes is selected

203

Page 204: PATE C_[1]

Pantech Academy of Technical Excellence

5. Locate your process in the Available Processes list based on the name of your

executable and click on it

6. Click the Attach button

7. Click OK

8. Click Close

9. Set a break point in the timer1_Elapsed method and wait for it to execute

204

Page 205: PATE C_[1]

Pantech Academy of Technical Excellence

GUI APPLICATION DEVELOPMENT

205

GUI Application Development

Windows Forms and Controls

Creating Menus

Tool Bars, Image List

Tree View, List View

Page 206: PATE C_[1]

Pantech Academy of Technical Excellence

Tool bars

Represents a Windows toolbar. ToolBar controls are used to display ToolBarButton

controls that can appear as a standard button, a toggle-style button, or a drop-down style

button. You can assign images to the buttons by creating an ImageList, assigning it to the

ImageList property of the toolbar, and assigning the image index value to the ImageIndex

property each ToolBarButton. You can then assign text to be displayed underneath or to the

right of the image by setting the Text property of the ToolBarButton.

Set the Appearance property of the toolbar to Flat to give the toolbar and its buttons a

flat appearance. As the mouse pointer moves over the buttons, their appearance changes to

three-dimensional. Toolbar buttons can be divided into logical groups by using separators. A

separator is a toolbar button with the Style property set to ToolBarButtonStyle.Separator.

Button separators appear as lines rather than spaces between the buttons when the toolbar has

a flat appearance. If the Appearance property is set to Normal, the toolbar buttons appear

raised and three-dimensional.

If you specify a value for the ButtonSize property, all buttons in the tool bar are

restricted to the specified size. Otherwise, the buttons adjust their size depending on their

content, and the ButtonSize property returns the initial size of the largest button.

To create a collection of ToolBarButton controls to display on the ToolBar, add the

buttons individually by using the Add or Insert methods of the Buttons property.

.NET Compact Framework Platform Note:  A Form supports only one ToolBar,

attempts to add an additional ToolBar throws a NotSupportedException.Adding a ToolBar to

any control besides a Form is not supported, such as to a Panel.

public class ToolBar : Control

The properties of the ToolBar class are listed here.

206

Page 207: PATE C_[1]

Pantech Academy of Technical Excellence

Tool bars Properties

Public Properties

AccessibilityObject Gets the AccessibleObject assigned to the control.

AccessibleDefaultActionDescriptio

n

Gets or sets the default action description of the

control for use by accessibility client applications.

AccessibleDescription Gets or sets the description of the control used by

accessibility client applications.

AccessibleName Gets or sets the name of the control used by

accessibility client applications.

AccessibleRole Gets or sets the accessible role of the control

AllowDrop Gets or sets a value indicating whether the control can

accept data that the user drags onto it.

Anchor Gets or sets which edges of the control are anchored

to the edges of its container.

Appearance Gets or set the value that determines the appearance

of a toolbar control and its buttons.

AutoSize

Protected Properties

Gets or sets a value indicating whether the toolbar

adjusts its size automatically, based on the size of the

buttons and the dock style.

Protected Properties

CreateParams Overridden. See Control.CreateParams.

DefaultImeMode Overridden. Gets the default Input Method Editor (IME) mode

supported by this control.

DefaultSize Overridden. See Control.DefaultSize.

DesignMode Gets a value that indicates whether the Component is currently in

207

Page 208: PATE C_[1]

Pantech Academy of Technical Excellence

design mode.

Events Gets the list of event handlers that are attached to this Component.

FontHeight Gets or sets the height of the font of the control.

ResizeRedraw Gets or sets a value indicating whether the control redraws itself

when resized.

ShowFocusCues Gets a value indicating whether the control should display focus

rectangles.

ShowKeyboardCues Gets a value indicating whether the control should display keyboard

shortcuts.

ToolBar Methods

The methods of the ToolBar class are listed here.

Public Methods

BeginInvoke Overloaded. Executes a delegate asynchronously on the thread that the

control's underlying handle was created on.

BringToFront Brings the control to the front of the z-order.

Contains Retrieves a value indicating whether the specified control is a child of

the control.

CreateControl Forces the creation of the control, including the creation of the handle

and any child controls.

Protected Methods

AccessibilityNotifyClients Notifies the accessibility client applications of the specified

AccessibleEvents for the specified child control.

208

Page 209: PATE C_[1]

Pantech Academy of Technical Excellence

CreateAccessibilityInstanc

e

Creates a new accessibility object for the control.

CreateControlsInstance Creates a new instance of the control collection for the control.

CreateHandle Overridden. See Control.CreateHandle.

DefWndProc Sends the specified message to the default window procedure.

ToolBar Events

The events of the ToolBar class are listed here.

Public Events

BindingContextChanged Occurs when the value of the BindingContext property changes.

ButtonClick Occurs when a ToolBarButton on the ToolBar is clicked.

ButtonDropDown Occurs when a drop-down style ToolBarButton or its down

arrow is clicked.

CausesValidationChanged Occurs when the value of the CausesValidation property

changes.

ChangeUICues Occurs when the focus or keyboard user interface (UI) cues

change

Image List

Provides methods to manage a collection of Image objects. This class cannot be

inherited.

public sealed class ImageList : Component

ImageList is typically used by other controls, such as the ListView, TreeView, or

ToolBar. You can add bitmaps, icons, or meta files to the ImageList, and the other controls

are able to use the images as they require.

209

Page 210: PATE C_[1]

Pantech Academy of Technical Excellence

ImageList uses a handle to manage the list of images. The Handle is not created until

certain operations, including getting the Count, getting the Handle, and calling Draw are

performed on the image list.

Image List Properties

The properties of the ImageList class are listed here.

Public Properties

ColorDepth Gets the color depth of the image list.

Container Gets the IContainer that contains the Component.

Handle Gets the handle of the image list object.

HandleCreated Gets a value indicating whether the underlying Win32 handle has

been created.

Images Gets the ImageList.ImageCollection for this image list.

ImageSize Gets or sets the size of the images in the image list.

ImageStream Gets the handle to the ImageListStreamer associated with this image

list.

Protected Properties

DesignMode Gets a value that indicates whether the Component is currently in

design mode.

210

Page 211: PATE C_[1]

Pantech Academy of Technical Excellence

Events Gets the list of event handlers that are attached to this Component.

ImageList Methods

The methods of the ImageList class are listed here.

Public Methods

CreateObjRef Creates an object that contains all the relevant information

required to generate a proxy used to communicate with a remote

object.

Dispose Overloaded. Releases the resources used by the Component.

Draw Overloaded. Draws the indicated image.

Equals Overloaded. Determines whether two Object instances are equal.

GetHashCode Serves as a hash function for a particular type, suitable for use in

hashing algorithms and data structures like a hash table.

GetLifetimeServic

e

Retrieves the current lifetime service object that controls the

lifetime policy for this instance.

Protected Methods

Dispose Overloaded. Overridden. See Component.Dispose.

211

Page 212: PATE C_[1]

Pantech Academy of Technical Excellence

Finalize Overridden. Releases unmanaged resources and performs other

cleanup operations before the Component is reclaimed by garbage

collection.

In C# and C++, finalizers are expressed using destructor syntax.

GetService Returns an object that represents a service provided by the

Component or by its Container.

MemberwiseClon

e

Creates a shallow copy of the current Object.

ImageList Events

The events of the ImageList class are listed here.

Public Events

Disposed (inherited from Component) Adds an event handler to listen to the

Disposed event on the component.

RecreateHandle Occurs when the Handle is recreated.

TreeView

Displays hierarchical data, such as a table of contents, in a tree structure.

Overview

The TreeView control is used to display hierarchical data, such as a table of

contents or file directory, in a tree structure and supports the following features:

Data binding that allows the nodes of the control to be bound to XML, tabular, or

relational data.

Site navigation through integration with the SiteMapDataSource control.

Node text that can be displayed as either plain text or hyperlinks.

Programmatic access to the TreeView object model to create trees, populate

nodes, set properties, and so on dynamically.

212

Page 213: PATE C_[1]

Pantech Academy of Technical Excellence

Client-side node population (on supported browsers).

The ability to display a check box next to each node.

Customizable appearance through themes, user-defined images, and styles.

Nodes

The TreeView control is made up of nodes. Each entry in the tree is called a node and is

represented by a TreeNode object. Node types are defined as follows:

A node that contains other nodes is called a parent node.

The node that is contained by another node is called a child node.

A node that has no children is called a leaf node.

The node that is not contained by any other node but is the ancestor to all the other

nodes is the root node.

A node can be both a parent and a child, but root, parent, and leaf nodes are mutually

exclusive. Several visual and behavioral properties of nodes are determined by whether a

node is a root, child, or leaf node.

Although a typical tree structure has only one root node, the TreeView control allows

you to add multiple root nodes to your tree structure. This is useful when you want to

display item listings without displaying a single root node, as in a list of product

categories.

Each node has a Text property and a Value property. The value of the Text property is

displayed in the TreeView, while the Value property is used to store any additional data

about the node, such as data that is passed to the postback event that is associated with the

node.

A node can be in one of two modes: selection mode and navigation mode. By default,

a node is in selection mode. To put a node into navigation mode, set the NavigateUrl

213

Page 214: PATE C_[1]

Pantech Academy of Technical Excellence

property for the node to a value other than an empty string (""). To put a node into

selection mode, set the NavigateUrl property for the node to an empty string ("").

Notes

Static Data

The simplest data model of the TreeView control is static data. To display static data

using declarative syntax, first nest opening and closing <Nodes> tags between the opening

and closing tags of the TreeView control. Next, create the tree structure by nesting

<asp:TreeNode> elements between the opening and closing <Nodes> tags. Each

<asp:TreeNode> element represents a node in the tree and maps to a TreeNode object. You

can set the properties of each node by setting the attributes of its <asp:TreeNode> element.

To create child nodes, nest additional <asp:TreeNode> elements between the opening and

closing <asp:TreeNode> tags of the parent node.

Binding to Data

The TreeView control can also be bound to data. You can use either of two methods

to bind the TreeView control to the appropriate data source type:

The TreeView control can use any data source control that implements the

IHierarchicalDataSource interface, such as an XmlDataSource control or a

214

Some Internet browsers have a limitation that can affect the performance of the TreeView

control. Microsoft Internet Explorer 6.0 has a URL character limit of 2067 characters that it

posts. If the number of characters in a URL of a node is larger than that number, expanding that

node will fail and no exception is thrown. A malicious user can create a callback request and get

data for the nodes of the TreeView control that the page developer is not displaying. Therefore,

security of the data must be implemented by the data source. Do not use the MaxDataBindDepth

property to hide data.

Page 215: PATE C_[1]

Pantech Academy of Technical Excellence

SiteMapDataSource control. To bind to a data source control, set the DataSourceID property

of the TreeView control to the ID value of the data source control. The TreeView control

automatically binds to the specified data source control. This is the preferred method to bind

to data.

The TreeView control can also be bound to an XmlDocument object or a DataSet

object with relations. To bind to one of these data sources, set the DataSource property of the

TreeView control to the data source, and then call the DataBind method.

When binding to a data source where each data item contains multiple properties

(such as an XML element with several attributes), a node displays the value that is returned

by the ToString method of the data item, by default. In the case of an XML element, the node

displays the element name, which shows the underlying structure of the tree but is not very

useful otherwise. You can bind a node to a specific data item property by specifying tree

node bindings using the DataBindings collection. The DataBindings collection contains

TreeNodeBinding objects that define the relationship between a data item and the node that it

is binding to. You can specify the criteria for binding and the data item property to display in

the node. For more information on tree node bindings, see TreeNodeBinding.

Dynamic Node Population

Sometimes, it is not practical to statically define the tree structure because the data

source returns too much data or because the data to display depends on information that you

get at run time. Because of this, the TreeView control supports dynamic node population.

When the PopulateOnDemand property for a node is set to true, that node gets populated at

run time when the node is expanded. To populate a node dynamically, you must define an

event-handling method that contains the logic to populate a node for the TreeNodePopulate

event.

Browsers that support callback scripts can also take advantage of client-side node

population. Client-side node population enables the TreeView control to populate a node

using client script when users expand the node, without requiring a round trip to the server.

For more information on client-side node population, see PopulateNodesFromClient.

215

Page 216: PATE C_[1]

Pantech Academy of Technical Excellence

Customizing the User Interface

There are many ways to customize the appearance of the TreeView control. First, you

can specify a different style (such as font size and color) for each of the node types.

If you use cascading style sheets (CSS) to customize the appearance of the control,

use either inline styles or a separate CSS file, but not both. Using both inline styles and a

separate CSS file could cause unexpected results. For more information on using style sheets

with controls, see ASP.NET Web Server Controls and CSS Styles.

The following table lists the available node styles.

Node style property Description

HoverNodeStyle The style settings for a node when the mouse

pointer is positioned over it.

LeafNodeStyle The style settings for the leaf nodes.

NodeStyle The default style settings for a node.

ParentNodeStyle The style settings for the parent nodes.

RootNodeStyle The style settings for the root node.

SelectedNodeStyle The style settings for a selected node.

You can also control the style of nodes at specific depths within the tree by using the

LevelStyles collection. The first style in the collection corresponds to the style of the nodes at

the first level in the tree. The second style in the collection corresponds to the style of the

nodes at the second level in the tree, and so on.

If a style is defined for a certain depth level using the LevelStyles collection, that style

overrides any root, parent, or leaf node style settings for the nodes at that depth.Another way

to alter the appearance of the control is to customize the images that are displayed in the

TreeView control. You can specify your own custom set of images for the different parts of

the control by setting the properties shown in the following table.

Image property Description

CollapseImageUrl The URL to an image displayed for the collapsible node indicator. This

216

Page 217: PATE C_[1]

Pantech Academy of Technical Excellence

image is usually a minus sign (-).

ExpandImageUrl The URL to an image displayed for the expandable node indicator. This

image is usually a plus sign (+).

LineImagesFolder The URL to the folder containing the line images used to connect parent

nodes to child nodes. The ShowLines property must also be set to true

for this property to have an effect.

NoExpandImageUrl The URL to an image displayed for the non-expandable node indicator.

Notes:

Each time the page is posted to the server, the CheckedNodes collection is

automatically populated with the selected nodes. When check boxes are displayed, you can

use the TreeNodeCheckChanged event to run a custom routine whenever the state of a check

box changes between posts to the server.

Events

The TreeView control provides several events that you can program against. This

allows you to run a custom routine whenever an event occurs. The following table lists the

events that are supported by the TreeView control.

Event Description

TreeNodeCheckChanged Occurs when the check boxes of the TreeView control change

217

Need to customize every image property. If an image property is not explicitly set, the built-in

default image is used.The TreeView control also allows you to display a check box next to a

node. When the ShowCheckBoxes property is set to a value other than TreeNodeTypes.

Page 218: PATE C_[1]

Pantech Academy of Technical Excellence

state between posts to the server.

SelectedNodeChanged

Occurs when a node is selected in the TreeView control.

TreeNodeExpanded Occurs when a node is expanded in the TreeView control.

TreeNodeCollapsed Occurs when a node is collapsed in the TreeView control.

TreeNodePopulate Occurs when a node with its PopulateOnDemand property set to

true is expanded in the TreeView control.

TreeNodeDataBound Occurs when a data item is bound to a node in the TreeView

control.

ListView Control

Represents a Windows list view control, which displays a collection of items that can

be displayed using one of four different views.

A ListView control allows you to display a list of items with item text and, optionally,

an icon to identify the type of item.

For example, the Windows Explorer list of files is similar in appearance to a ListView

control. It displays a list of the files and folders currently selected in the tree. Each file and

folder displays an icon associated with it to help identify the type of file or folder.

The ListViewItem class represents an item within a ListView control. The items that

are displayed in the list can be shown in one of four different views. Items can be displayed

as large icons, as small icons, or as small icons in a vertical list. Items can also have subitems

which contain information that is related to the parent item.

The fourth view style, details view, allows you to display the item and its subitems in

a grid with column headers that identify the information being displayed in a subitem.

ListView supports single or multiple selection. The multiple selection feature lets the user

select from a list of items in a way similar to a ListBox control. Additionally, the user can

218

Page 219: PATE C_[1]

Pantech Academy of Technical Excellence

activate selected items to perform a task. For example, you could use a ListView control to

display a list of files that the application can then open and utilize.

The user can select the files to open and then double-click them to activate the items

and open the files in the application. The ListView can also display check boxes, using the

CheckBoxes property, to allow the user to check the items that they want to perform an

action on. You can use the ListView control in a variety of ways. The control can be used to

display information from an application, a database, or a text file. The ListView can also be

used to obtain information from the user, such as selecting a set of files to process.

ListView provides a large number of properties that provide flexibility in appearance

and behavior. The View property allows you to change the way in which items are displayed.

The LargeImageList, SmallImageList, and StateImageList properties allow you to specify the

ImageList objects that contain the images displayed for items and, in the case of the

StateImageList, the check boxes that are displayed when the CheckBoxes property is set to

true.

To determine which items are checked, you can use the CheckedItems property to

access the ListView.CheckedListViewItemCollection collection. The Columns property

allows access to the ListView.ColumnHeaderCollection, which stores the column headers

that are displayed when the View property of the control is set to View.Details. Items are

added and removed from the ListView through the Items property.

The Items property allows you to access the ListView.ListViewItemCollection of the

control, which provides methods for manipulating the items in the control. If you want to

allow the user to edit the text of an item, you can use the LabelEdit property. When your

control contains a large number of items, it is often easier for the user to see them in a sorted

list. You can use the Sorting property to sort the items alphabetically.

Many of the properties of the ListView control are used when the View property of

the control is set to View.Details. The AllowColumnReorder property allows the user of your

ListView control to reconfigure the order of columns at run time. The FullRowSelect

property allows an item and its subitems to be selected instead of just the item. To display

grid lines in the details view to identify the boundaries of items and subitems in the ListView,

219

Page 220: PATE C_[1]

Pantech Academy of Technical Excellence

you can use the GridLines property. The HeaderStyle property allows you to specify the type

of column headers to display.

In addition to the many properties that are available for a ListView control, there are

methods and events that your application can use to provide additional capabilities to the

ListView. The BeginUpdate and EndUpdate methods allow you to add many items to a

ListView without displaying the repainting of the control each time an item is added,

improving performance. If your ListView control is displaying items and subitems, you may

want to provide functionality when the user right-clicks a subitem. To determine the item

whose subitem is being clicked, you can use the GetItemAt method. When performing

validation of the items after the user has edited them, you may want to display a specific item

to the user to change. The EnsureVisible method can be called to ensure that the specific item

is in the visible area of the control.

If the LabelEdit property set to true, you can perform tasks such as validating the text

being edited before and after the text changed by creating an event handler for the

BeforeLabelEdit and AfterLabelEdit events. To perform tasks such as opening a file or

displaying a dialog box to edit an item displayed in a ListView, you can create an event

handler for the ItemActivate event.

If you allow the user to sort the items in a ListView when they click a column header,

you can create an event handler for the ColumnClick event to perform the sorting. When the

CheckBoxes property is set to true, you can determine when a change in an item's check state

has occurred by handling the ItemCheck event.

DATA BASE PROGRAMMING (ADO.NET) WITH C#

220

Page 221: PATE C_[1]

Pantech Academy of Technical Excellence

Data Base Programming (ADO.NET) with C#

ADO .NET Introduction

Data Providers in .Net

Introduction to Managed and Unmanaged Providers

Data Readers, Dataset and Data Adapters

Datagrid View

SQL Datasource

Creating Relations and Transactions

ADO .NET INTRODUCTION

221

Page 222: PATE C_[1]

Pantech Academy of Technical Excellence

The first data access model, DAO (data access model) was created for local databases

with the built-in Jet engine which had performance and functionality issues. Next came RDO

(Remote Data Object) and ADO (Active Data Object) which were designed for Client Server

architectures but soon ADO took over RDO. ADO was a good architecture but as the

language changes so is the technology. With ADO, all the data is contained in a record set

object which had problems when implemented on the network and penetrating firewalls.

ADO was a connected data access, which means that when a connection to the database is

established the connection remains open until the application is closed. Leaving the

connection open for the lifetime of the application raises concerns about database security

and network traffic. Also, as databases are becoming increasingly important and as they are

serving more people, a connected data access model makes us think about its productivity.

For example, an application with connected data access may do well when connected to two

clients, the same may do poorly when connected to 10 and might be unusable when

connected to 100 or more. Also, open database connections use system resources to a

maximum extent making the system performance less effective.

Most applications need data access at one point of time making it a crucial component

when working with applications. Data access is making the application interact with a

database, where all the data is stored. Different applications have different requirements for

database access. C# .NET uses ADO .NET (Active X Data Object) as its data access and

manipulation protocol which also enables us to work with data on the Internet. Let's take a

look why ADO .NET came into picture replacing ADO.

Data Providers in .Net

The Data Provider is responsible for providing and maintaining the connection to the

database. A Data Provider is a set of related components that work together to provide data in

an efficient and performance driven manner. The .NET Framework currently comes with two

Data Providers: the SQL Data Provider which is designed only to work with Microsoft's SQL

Server 7.0 or later and the OleDb Data Provider which allows us to connect to other types of

databases like Access and SQL.

222

Page 223: PATE C_[1]

Pantech Academy of Technical Excellence

..NET Data ProvidersNET Data Providers

Namespaces

Namespaces is called as collection of class libraries.

• System. Data & System.Data.Common

• System.Data.SqlClient & System.Data.OleDB

• System.Data.SqlTypes

• System.XML & System.XML.Schema

C#

using System.Data;

using System.Data.SqlClient;

SqlDataAdapter sqlAdp= new SqlDataAdapter();

Introduction to Managed and Unmanaged Providers

Managed Providers

The UDA(Universal Data Access) managed .NET Data Provider delivers robust and

secure data connectivity across all Databases support in the Universal Data Access suite,

including all major databases - Microsoft SQL Server, Oracle, DB2, Sybase, Ingres II,

Client

SQL .NET

Data Provider

OLE DB .NET

Data Provider

ODBC .NET

Data Provider

OLE DB

Provider

ODBC

Driver

SQL SERVER

Other DB

Other DB

223

Page 224: PATE C_[1]

Pantech Academy of Technical Excellence

Informix and Progress. The .NET Data Provider is built with managed code, enabling it to

running completely within the .NET Framework runtime delivering better security and

performance. This Generic managed .Net Data Provider connects to the remote data source

via one of two forms currently:

Multi-Tier Database Agents

The OpenLink VDB (Virtual Database) layer has been ported to C# and linked into the

Provider, enabling it to communicate directly with the OpenLink Multi-Tier Database agents

installed on the remote machine.

Example:

using System.Data.SqlTypes;

TDS(Tabular Data Stream) Protocol

The TDS protocol has been ported to C# and linked into the Provider, enabling two

Managed Providers to be created capable of direct connectivity to Microsoft and Sybase

SQLServer Databases without the need for any additional components on the Server

Example:

using System.Data.OleDb;

Unmanaged Providers

The UDA (Universal Data Access) Unmanaged .NET Data Provider enables

connectivity to any ODBC Data Source by acting as a Bridge between ADO.Net and ODBC.

This Provider is provided as a stop-gap solution enabling connectivity to Data source for

which managed .Net Providers are not already available as indicated in the diagram below,

and as such does not provide the benefits of security and performance available from its

Managed counterpart:

Example:

using System.Data.Odbc;

224

Page 225: PATE C_[1]

Pantech Academy of Technical Excellence

Data Readers, Dataset and Data Adapters

The DataReader Object

The DataReader object provides a forward-only, read-only, connected stream

recordset from a database. Unlike other components of the Data Provider, DataReader objects

cannot be directly instantiated. Rather, the DataReader is returned as the result of the

Command object's ExecuteReader method. The SqlCommand.ExecuteReader method returns

a SqlDataReader object, and the OleDbCommand.ExecuteReader method returns an

OleDbDataReader object. The DataReader can provide rows of data directly to application

logic when you do not need to keep the data cached in memory. Because only one row is in

memory at a time, the DataReader provides the lowest overhead in terms of system

performance but requires the exclusive use of an open Connection object for the lifetime of

the DataReader.

C#.Net

SqlDataReader sqlReader;

sqlReader = sqlCommand.ExecuteReader();

while (sqlReader.Read())

{

// process, sqlReader("field")

}

sqlReader.Dispose();

The DataAdapter Object

The DataAdapter is the class at the core of ADO .NET's disconnected data access. It

is essentially the middleman facilitating all communication between the database and a

DataSet. The DataAdapter is used either to fill a DataTable or DataSet with data from the

database with it's Fill method. After the memory-resident data has been manipulated, the

DataAdapter can commit the changes to the database by calling the Update method.

225

Page 226: PATE C_[1]

Pantech Academy of Technical Excellence

C#.Net

SqlDataAdapter sqlDA= new SqlDataAdapter();

sqlDA. SelectCommand=new SqlCommand ("select * from authors“, sqlConnection);

DataSet sqlDS = new DataSet("authorsTable");

sqlDA.Fill(sqlDS, "authorsTable");

DataSets

The dataset is a disconnected, in-memory representation of data. It can be considered

as a local copy of the relevant portions of the database. The Dataset is persisted in memory

and the data in it can be manipulated and updated independent of the database. When the use

of this Dataset is finished, changes can be made back to the central database for updating.

The data in Dataset can be loaded from any valid data source like Microsoft SQL server

database, an SQL database or from a Microsoft Access database.

Creating DataSets

• Setup SqlConnection

• Setup a SqlDataAdapter

• Create a DataSet

• Call the .Fill() method on the DA

Syntax:

SqlConnection myConnection = new SqlConnection(connectionString);

SqlDataAdapter ad = new SqlDataAdapter("SELECT * FROM Categories", myConnection);

DataSet ds = new DataSet();

ad.Fill(ds, "Categories");

myGridView.DataSource = ds;

myGridView.DataBind();

226

Page 227: PATE C_[1]

Pantech Academy of Technical Excellence

Datagrid View

DataGrid requires you to write custom code for handling common operations like

sorting, paging and manipulation of data in DataGrid

DataGrid when bound to DataSource control can only support select operation on

DataSource. Updating DataSource through DataGrid can be done only through

custom ADO.NET code

DataGrid supports a restricted event model.

DataGrid does not support adaptive rendering on different platforms.

SQL Data source

DataSource controls enable programmers to declaratively connect data sources to the

user interface. The logic for retrieving the data from the source is inbuilt into the control. For

instance when a DropDownList is added to the form the developer is prompted to connect to

the DataSource.

Creating SQL DataSoutrce By using following steps:

Step1:

On clicking ‘connect to DataSource’, the wizard is started to guide the user through

the process of setting up the data source.

Step2:

Check whether the user views existing datasource or new datasource. The user has to

indicate whether an existing data source or a new data source has to be added.

Step3:

Create a new SQLDataSource. byChoose a DataSource drop down box, select < New

DataSource > The next screen of the wizard prompts the user select the type of data source

required. The user has to select the database and specify an ID for the DataSource. Click Ok

to continue

227

Page 228: PATE C_[1]

Pantech Academy of Technical Excellence

Step4:

A connection string will now have to be specified. The connection can be an existing

string or a new string. Since there are no existing connections a new connection will be

created. Click on New Connection to create the connection string. A number of options are

given to the user. Select Sql Server Database file to connect to the SQL Server Express

database.

Step5:

On clicking continue the user is prompted to select an existing data source or to click

change to change the data source or provider. The user has to also enter the name of the new

database or an existing data base. Name the new database as ExForSys and click Test

Connection (Succeeded).

Step6:

The next string prompts the user to save the connection string to the application

configuration file. The user has to click on the check box if ‘yes’ and then click Next to

create queries.

Query:

SqlConnection myConnection = new SqlConnection(connectionString);

SqlDataAdapter ad = new SqlDataAdapter("SELECT * FROM Categories", myConnection);

DataSet ds = new DataSet();

ad.Fill(ds, "Categories");

myGridView.DataSource = ds;

myGridView.DataBind();

Creating Relations and Transactions

A transaction is a group of operations combined into a logical unit of work that is

either guaranteed to be executed as a whole or rolled back. Transactions help the database in

satisfying all the ACID (Atomic, Consistent, Isolated, and Durable). Transaction processing

is an indispensable part of ADO.NET. It guarantees that a block of statements will either be

executed in its entirety or rolled back,( i.e., none of the statements will be executed).

228

Page 229: PATE C_[1]

Pantech Academy of Technical Excellence

Implementing Transactions in ADO.NET

ADO.NET, the transactions are started by calling the BeginTransaction method of the

connection class. This method returns an object of type SqlTransaction. Once you are done

executing the necessary statements within the transaction unit/block, make a call to the

Commit method of the given SqlTransaction object, or you can roll back the transaction using

the Rollback method, depending on your requirements (if any error occurs when the

transaction unit/block was executed).

Transactions are supported in ADO.NET by the SqlTransaction class that belongs to

the System.Data.SqlClient namespace.

The two main properties of this class are as follows:

Connection:

This indicates the SqlConnection instance that the transaction instance is

associated with

IsolationLevel:

This specifies the IsolationLevel of the transaction

The following are the methods of this class that are noteworthy:

Commit() This method is called to commit the transaction

Rollback() This method can be invoked to roll back a transaction. Note that a transaction

can only be rolled back after it has been committed.

Save() This method creates a save point in the transaction. This save point can be used to

rollback a portion of the transaction at a later point in time. The following are the steps to

implement transaction processing in ADO.NET.

Connect to the database

Create a SqlCommand instance with the necessary parameters

Open the database connection using the connection instance

Call the BeginTransaction method of the Connection object to mark the beginning

of the transaction

Execute the sql statements using the command instance

229

Page 230: PATE C_[1]

Pantech Academy of Technical Excellence

Call the Commit method of the Transaction object to complete the transaction, or

the Rollback method to cancel or abort the transaction

Close the connection to the database

The following code snippet shows how we can implement transaction processing using

ADO.NET in our applications.

Example:

string connectionString = ...; //Some connection string

SqlConnection sqlConnection = new SqlConnection(connectionString);

sqlConnection.Open();

SqlTransaction sqlTransaction = sqlConnection.BeginTransaction();

SqlCommand sqlCommand = new SqlCommand();

sqlCommand.Transaction = sqlTransaction;

try

{

sqlCommand.CommandText = "Insert into Employee (EmpCode, EmpName) VALUES (1,

'Joydip')";

sqlCommand.ExecuteNonQuery();

sqlCommand.CommandText = "Insert into Dept (DeptCode, DeptName, EmpCode)

VALUES (9, 'Software', 1)";

sqlCommand.ExecuteNonQuery();

sqlTransaction.Commit();

//Usual code

}

catch(Exception e)

{

sqlTransaction.Rollback();

//Usual code

}

230

Page 231: PATE C_[1]

Pantech Academy of Technical Excellence

finally

{

sqlConnection.Close();

}

231