Top Banner
TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53) .Net Programming Syllabus Module 1 Understanding previous states of affairs, The .Net Solution, The Building Block of the .Net Platform (CLR, CTS and CLS), The Role of the .Net Base Class Libraries, What C# Brings to the Table, An Overview of .Net Binaries (or Assemblies), The Role of the Common Intermediate Language, The Role of .Net Type Metadata, The Role of the Assembly Manifest, Compiling CIL to Platform Specific Instructions. Understanding the common type system, Intrinsic CTS Data Types, Understanding the Common Languages Specification, Understanding the Common Language Runtime, A tour of the .Net Namespaces, Increasing Your Namespace Nomenclature, Deploying the .NET Runtime. Role of Command Line Compiler (csc.exe), Building C# Applications using csc.exe, Working with csc.exe Response Files, Generating Bug Reports, Remaining C# Compiler Options, The Command Line Debugger (cordbg.exe), Using the Visual Studio.NET IDE, The C# “Pre-processor” Directives, An Interesting Aside: System.Environment Class. R.V.COLLEGE OF ENGINEERING Page 1
510
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

.Net Programming

Syllabus

Module 1

Understanding previous states of affairs, The .Net Solution, The Building Block of the .Net Platform (CLR, CTS and CLS), The Role of the .Net Base Class Libraries, What C# Brings to the Table, An Overview of .Net Binaries (or Assemblies), The Role of the Common Intermediate Language, The Role of .Net Type Metadata, The Role of the Assembly Manifest, Compiling CIL to Platform Specific Instructions.

Understanding the common type system, Intrinsic CTS Data Types, Understanding the Common Languages Specification, Understanding the Common Language Runtime, A tour of the .Net Namespaces, Increasing Your Namespace Nomenclature, Deploying the .NET Runtime.

Role of Command Line Compiler (csc.exe), Building C# Applications using csc.exe, Working with csc.exe Response Files, Generating Bug Reports, Remaining C# Compiler Options, The Command Line Debugger (cordbg.exe), Using the Visual Studio.NET IDE, The C# “Pre-processor” Directives, An Interesting Aside: System.Environment Class.

The Anatomy of a Basic C# Class, Creating Objects: Constructor Basics, The Composition of a C# Application, Default Assignment and Variable scope, The C# Member Initialization Syntax, Basic Input and Output with the Console Class,

R.V.COLLEGE OF ENGINEERING Page 1

Page 2: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Defining Program Constants, C# Iteration Constructs, C# Controls Flow Constructs, The Complete set of C# Operators.

Understanding Value Types and Reference Types, The Master Node: System.Object, The System Data Types (and C# Aliases), Converting between value types reference types: Boxing and Unboxing.

Defining Custom Class Methods, Understanding Static Methods, Methods Parameter Modifiers, Array Manipulation in C#, String Manipulation in C#, C# Enumerations, Defining Structures in C#, Defining Custom Namespaces.

Formal Definition of the C# Class, Definition the “Default Public Interface” of a Type, Recapping the Pillars of OOP, The First Pillars: C#’s Encapsulation Services, Pseudo Encapsulation: Creating Read-Only Fields.

The Second Pillar: C#’s Inheritance Supports, Keeping family secrets: The “Protected” Keyword, Nested Type Definitions, The Third Pillar: C#’s Polymorphic Support, Casting Between.

Meaning of Errors and Exceptions, The Role of .NET Exception Handling, The System. Exception Base Class, Throwing a Generic Exception, Catching Exception, CLR System – Level Exception (System.SystemException), Custom Application-Level Exception (System.ApplicationException), Handling Multiple Exceptions, The Finally Block, Dynamically Identifying Application and System Level Exceptions.

Understanding Object Lifetime, The CIL of new, The Basics of Garbage Collection, Finalization a type, The Finalization Process, Building an AD Hoc Destruction Method, Garbage Collection Optimizations, The System. GC Type.

Defining Interfaces Using C#, Invoking Interface Members at the object level, Exercising the shapes hierarchy, Understanding Explicit Interface Implementation, Interfaces as Polymorphic Agents, Building Interface Hierarchies.

R.V.COLLEGE OF ENGINEERING Page 2

Page 3: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Understanding the IConvertible Interface, Building a Custom Enumerator (IEnummerable and Enumerator), Building Cloneable objects (ICloneable), Building Comparable Objects (IComparable), Exploring the System.Collections Namespace.

Understanding Callback Interfaces, Understanding the .NET Delegate Type, Members of System.Multicast Delegate, The Simplest Possible Delegate Example, Building More Elaborate Delegate Example, Understanding Asynchronous Delegates, Understanding (and Using) Events.

The advanced keywords of C#, Building a Custom Indexer, Overloading operators, The Internal Representation of Overloading Operators, Creating Custom Conversion Routines, Defining Implicit Conversion Routines.

An Overview of .NET Assemblies, Core Benefits of Assemblies, Building a Single File Test Assembly, Exploring the Manifest, Building a Multifile Assembly.

Understanding Private Assemblies, Probing for Private Assemblies (The Basics), Private Assemblies and XML Configuration Files, Probing for Private Assemblies (The Details), Understanding Shared Assembly, Understanding Strong Names, Building a Shared Assembly, Understanding Delayed Signing, Installing/Removing Shared Assembly, Using a Shared Assembly.

R.V.COLLEGE OF ENGINEERING Page 3

Page 4: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

.NET Programming

Module 1

Unit 1

CONTENTS:

1.1 Objectives1.2 Introduction1.3 Understanding previous states of affairs1.4 The .Net Solution1.5 The Building Block of the .Net Platform (CLR, CTS and CLS)1.6 The Role of the .Net Base Class Libraries1.7 What C# Brings to the Table1.8 An Overview of .Net Binaries (or Assemblies)1.9 The Role of the Common Intermediate Language1.10 The Role of .Net Type Metadata1.11 The Role of the Assembly Manifest 1.12 Compiling CIL to Platform Specific Instructions1.13 Summary1.14 Keywords1.15 Exercises

1.1 Objectives

At the end of this lesson, the students will understand:

The problems with previous programming languages The solution provided by .NET Building blocks of .NET viz. CLR, CTS and CLS The role of Base Class Libraries (BCL) The role of CIL, Metadata and Assembly manifest

R.V.COLLEGE OF ENGINEERING Page 4

Page 5: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

1.2 Introduction

However good a programming language is, it will be overshadowed by something

better in the course of time. The languages like C, C++, Visual Basic, Java, the

frameworks like MFC (Microsoft Foundation Classes), ATL(Active Template Library),

STL(Standard Template Library) and the architectures like COM (Component Object

Model), CORBA (Common Object Request Broker Architecture), EJB (Enterprise

JavaBeans) etc. were possessing technologies which is needed by the programmer.

But still, the hunt for better one will be going on even in future too.

1.3 Understanding previous states of affairs

Before examining the specifics of the .NET universe, it’s helpful to consider some of

the issues that motivated the genesis of Microsoft’s current platform. To get in the

proper idea, let us discuss some of the limitations of previous technologies.

Life as a C/Win32 API Programmer

Building windows applications using the raw API (Application Programming

Interface) and C is a complex task.

C is a very abrupt language.

C developers have to perform manual memory management.

C involves ugly pointer arithmetic, and ugly syntactical constructs.

C is a structured language and so lacks the benefits provided by the object-

oriented approach.

When you combine the thousands of global functions and data types defined

by the Win32 API to a difficult language like C, bugs will increase rapidly.

Life as a C++/MFC Programmer

R.V.COLLEGE OF ENGINEERING Page 5

Page 6: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

The improvement over raw C/API development is the use of the C++

programming language.

Though C++ provides OOPs concepts like encapsulation, inheritance and

polymorphism, it is not away from manual memory management and

pointers.

Even with difficulty, many C++ frameworks exist today. For example, the

Microsoft Foundation Classes (MFC) provides the developer with a set of C++

classes that facilitate the construction of Win32 applications.

The main role of MFC is to wrap a “sane subset” of the raw Win32 API behind

a number of classes, magic macros, and numerous code-generation tools.

Regardless of the helpful assistance offered by the MFC framework, C++

programming remains a difficult and error-prone experience, given its

historical roots in C.

Life as a Visual Basic 6.0 Programmer

VB6 is popular due to its ability to build complex user interfaces, code

libraries, and simpler data access logic.

Even more than MFC, VB6 hides the complexities of the raw Win32 API from

view using a number of integrated code wizards, intrinsic data types, classes,

and VB-specific functions.

The major downfall of VB6 is that it is not a fully object-oriented language.

For example, VB6 does not allow the programmer to establish “is-a”

relationships between types.

VB6 has no intrinsic support for parameterized class construction.

VB6 doesn’t provide the ability to build multithreaded applications.

Life as a Java/J2EE Programmer

Java has greater strength because of its platform independence nature.

Java cleans up many unsavory syntactical aspects of C++.

Java provides programmers with a large number of predefined “packages”

that contain various type definitions.

R.V.COLLEGE OF ENGINEERING Page 6

Page 7: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Although Java is a very elegant language, one potential problem is that using

Java typically means that you must use Java front-to-back during the

development cycle.

So, language integration is difficult in Java, which is against its primary goal

(a single programming language for every need).

Pure Java is simply not appropriate for many graphically or numerically

intensive applications.

For graphics oriented product, Java works slowly and compared to this, C++

or C would execute faster.

Java provides a limited ability to access non-Java APIs and hence, there is

little support for true cross-language integration.

Life as a COM Programmer

COM is a group of classes, which works as a block of reusable code.

The binary COM server can be accessed in a language-independent manner.

For example, COM classes written using C++ can be used by VB6.

But, COM’s language independence is somewhat limited as it will not support

inheritance. Rather, one must make use of “has-a” relationship to reuse COM

class types.

Although COM can be considered a very successful object model, it is

extremely complex under the internally.

To help simplify the development of COM binaries, numerous COM-aware

frameworks have come into existence.

Even if we choose a relatively simple COM-aware language such as VB6, we

are still forced to contend with fragile registration entries and numerous

deployment-related issues.

Life as a Windows DNA Programmer

The popularity of Web applications is ever expanding.

Sadly, building a web application using COM-based Windows DNA (Distributed

interNet Applications) is quite complex.

R.V.COLLEGE OF ENGINEERING Page 7

Page 8: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Some of this complexity is because Windows DNA requires the use of

numerous technologies and languages like ASP, HTML, XML, JavaScript,

VBScript, ADO etc.

Many of these technologies are completely unrelated from a syntactic point

of view.

Also each language and/or technology has its own type system. For example,

an “int” in JavaScript is not quite the same as an “Integer” in VB6.

1.4 The .NET Solution

For various problems faced in previous technologies, the .NET provides the solution.

The .NET framework is a completely new model for building systems on the

Windows family of operating systems, as well as on numerous non-Microsoft

operating systems such as Mac OS X and various Unix/Linux distributions. Some

core features provided by .NET are as follows:

Full interoperability with existing code: Existing COM binaries can

mingle/interop with newer .NET binaries and vice versa. Also, Platform

Invocation Services allows to call C-based libraries (including the underlying

API of the operating system) from .NET code.

Complete and total language integration: Unlike COM, .NET supports

cross-language inheritance, cross-language exception handling, and cross-

language debugging.

A common runtime engine shared by all .NET-aware languages: One

aspect of this engine is a well-defined set of types that each .NET-aware

language “understands.”

A base class library: This library protects the programmer from the

complexities of raw API calls and offers a consistent object model used by

all .NET-aware languages.

R.V.COLLEGE OF ENGINEERING Page 8

Page 9: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

No more COM plumbing: IClassFactory, IUnknown, IDispatch, IDL code, and

VARIANT-compliant data types (BSTR, SAFEARRAY, and so forth) have no

place in a native .NET binary.

A truly simplified deployment model: Under .NET, there is no need to

register a binary unit into the system registry. Furthermore, .NET allows

multiple versions of the same *.dll to exist on a single machine.

NOTE: The .NET platform has nothing to do with COM. In fact, the only way .NET

and COM types can interact with each other is using the interoperability layer.

1.5 The Building Blocks of .NET Platform

The entities that make .NET to provide several benefits are CLR, CTS, and CLS.

The .NET can be understood as a new runtime environment and a comprehensive

base class library.

CLR:

The runtime layer is properly referred to as the Common Language

Runtime (CLR).

The primary role of the CLR is to locate, load, and manage .NET types.

The CLR also takes care of a number of low-level details such as memory

management and performing security checks.

CTS:

The Common Type System (CTS) specification fully describes the entities

like all possible data types and programming constructs supported by the

runtime.

It specifies how these entities can interact with each other.

It also specifies how they are represented in the .NET metadata format.

R.V.COLLEGE OF ENGINEERING Page 9

Page 10: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

CLS:

A given .NET –aware language might not support each and every feature

defined by the CTS.

The Common Language Specification (CLS) is a related specification that

defines a subset of common types and programming constructs that all .NET

programming languages can agree on.

Thus, the .NET types that expose CLS-compliant features can be used by

all .NET-aware languages.

But, a data type or programming construct, which is outside the bounds of

the CLS, may not be used by every .NET programming language.

1.6 The Role of Base Class Libraries

In addition to the CLR and CTS/CLS specifications, the .NET platform provides a base

class library that is available to all .NET programming languages. This base class

library encapsulates various primitives such as threads, file input/output (I/O),

graphical rendering, and interaction with various external hardware devices. It also

provides support for a number of services required by most real-world applications.

For example, the base class libraries define types

R.V.COLLEGE OF ENGINEERING Page 10

The Base Class Libraries

Data Access GUI Security XML/SOAP

Threading FILE I/O Debugging (et al.)

The Common Language Runtime

Common Type SystemCommon Language Specification

Page 11: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Figure 1.1 The CLR, CTS, CLS, and base class library relationship

that facilitate database access, XML manipulation, programmatic security, and the

construction of web-enabled, traditional desktop and console-based front ends.

From a high level, you can visualize the relationship between the CLR, CTS, CLS,

and the base class library, as shown in Figure 1.1.

1.7 What C# Brings to the Table

C# is a programming language that looks very similar to the syntax of Java. Many of

the syntactic constructs of C# are taken from various aspects of Visual Basic 6.0

and C++. For example, like VB6, C# supports the notion of formal type properties,

and the ability to declare methods taking varying number of arguments. Like C++,

R.V.COLLEGE OF ENGINEERING Page 11

Page 12: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

C# allows you to overload operators, as well as to create structures, enumerations,

and callback functions (via delegates).

The features of C# language can be put together as –

No pointers required! C# programs typically have no need for direct pointer

manipulation

Automatic memory management through garbage collection. Given this, C#

does not support a delete keyword.

Formal syntactic constructs for enumerations, structures, and class

properties.

The C++-like ability to overload operators for a custom type, without the

complexity.

The syntax for building generic types and generic members is very similar to

C++ templates.

Full support for interface-based programming techniques.

Full support for aspect-oriented programming (AOP) techniques via attributes.

This brand of development allows you to assign characteristics to types and

their members to further qualify their behavior.

C# produces the code that can execute within the .NET runtime. The code

targeting the .NET runtime is called as managed code. The binary unit that

contains the managed code is termed as assembly. Conversely, code that cannot

be directly hosted by the .NET runtime is termed unmanaged code.

1.8 An Overview of .NET Assemblies (or Binaries)The .NET binaries are not described using COM type libraries and are not registered

into the system registry. The .NET binaries do not contain platform-specific

instructions, but rather platform-agnostic intermediate language (IL) and type

metadata. The relationship between .NET aware compilers and metadata are shown

in Fig. 1.2.

R.V.COLLEGE OF ENGINEERING Page 12

Page 13: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Note: The terms IL, MSIL (Microsoft Intermediate Language) and CIL (Common

Intermediate Language) are all describing the same exact entity.

Figure 1.2 All .NET-aware compilers produce IL instructions and metadata.

Few points to be understood about binaries/assemblies are:

When a *.dll or *.exe has been created using a .NET-aware compiler, the

resulting module is bundled into an assembly.

R.V.COLLEGE OF ENGINEERING Page 13

C# Source Code

Perl to Perl .NET Source Code

COBOL to COBOL. NET Source Code

C++ to MC++ Source Code

MSIL

and

Metadata

(DLL or EXE)

C# Compiler

Perl to Perl .NET Compiler

COBOL to COBOL. NET Compiler

C++ to MC++ Compiler

Page 14: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

An assembly contains CIL code, (which is conceptually similar to Java

bytecode). This is not compiled to platform-specific instructions until

absolutely necessary.

When a block of CIL instructions (such as a method implementation) is

referenced for use by the .NET runtime engine, CIL code will be compiled.

Assemblies also contain metadata that describes the characteristics of every

“type” living within the binary, in detail. For example, if you have a class

named SportsCar, the type metadata describes details such as SportsCar’s

base class, which interfaces are implemented by SportsCar (if any), as well as

a full description of each member supported by the SportsCar type.

Unlike COM, the .NET metadata is always present and is automatically

generated by a given .NET-aware compiler.

In addition to CIL and type metadata, assemblies themselves are also

described using metadata, which is officially termed as a manifest.

The manifest contains information about the current version of the assembly,

culture information (used for localizing string and image resources), and a list

of all externally referenced assemblies that are required for proper execution.

Single-File and Multifile Assemblies

If an assembly is composed of a single *.dll or *.exe module, you have a single-file

assembly. A single-file assembly contains the assembly manifest, the type

metadata, the CIL code, and the resources. Figure 1.3 shows a single-file assembly

and its contents.

Multifile assemblies are composed of numerous .NET binaries, each of which is

termed a module. When building a multifile assembly, one of these modules

(termed the primary module) must contain the assembly manifest (and possibly CIL

instructions and metadata for various types). The other related modules contain a

module level manifest, CIL, and type metadata. The primary module maintains the

set of required secondary modules within the assembly manifest.

MyApp.dll

R.V.COLLEGE OF ENGINEERING Page 14

Page 15: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Figure 1.3 Single-File Assembly

In other words, multifile assemblies are used when different modules of the

application are written in different languages. Multifile assemblies make the

downloading process more efficient. They enable you to store the seldom used

types in separate modules and download them only when needed. The multifile

assembly shown in Figure 1.4 consists of three files. The MyApp.dll file contains the

assembly manifest for the multifile assembly. The MyLib.netmodule file contains the

type metadata and the MSIL code but not the assembly manifest. The Employee.gif

is the resource file for this multifile assembly.

MyApp.dll

MyLib.netmodule Employee.gif

Figure 1.4 MultiFile Assembly

R.V.COLLEGE OF ENGINEERING Page 15

Assembly Metadata

Resources

CIL Code

Type Metadata

CIL

Type Metadata

Assembly Manifest

CIL

Type Metadata

Page 16: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Thus, an assembly is really a logical grouping of one or more related modules that

are intended to be initially deployed and versioned as a single unit.

1.9 The Role of Common Intermediate Language

CIL is a language that sits above any particular platform-specific instruction set.

Regardless of which .NET-aware language you choose (like C#, VB.NET, VC++.NET

etc), the associated compiler produces CIL instructions. Once the C# compiler

(csc.exe) compiles the source code file, you end up with a single-file *.exe assembly

that contains a manifest, CIL instructions, and metadata describing each aspect of

the program.

Benefits of CIL

The benefits of compiling source code into CIL rather than directly to a specific

instruction set are as given below:

Language integration: Each .NET-aware compiler produces nearly identical

CIL instructions. Therefore, all languages are able to interact within a well-

defined binary arena.

Given that CIL is platform-agnostic, the .NET Framework itself is platform-

agnostic. So a single code base can run on numerous operating systems, just

like Java.

There is an international standard for the C# language, and a large subset of

the .NET platform and implementations already exist for many non-Windows

operating systems. In contrast to Java, the .NET allows you to build applications

using your language of choice.

1.10 The Role .NET Type Metadata

R.V.COLLEGE OF ENGINEERING Page 16

Page 17: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

In addition to CIL instructions, a .NET assembly contains full, complete, and

accurate metadata. Few points about metadata are described hereunder:

The metadata describes each and every type (class, structure, enumeration

etc.) defined in the binary, as well as the members of each type (properties,

methods, events etc.).

It is always the job of the compiler (not the programmer) to produce the

latest and greatest type metadata.

As .NET metadata is so careful, assemblies are completely self-describing

entities and so .NET binaries have no need to be registered into the system

registry.

Metadata is used by numerous aspects of the .NET runtime environment, as

well as by various development tools.

For example, the IntelliSense feature provided by Visual Studio 2005 is made

possible by reading an assembly’s metadata at design time.

Metadata is also used by various object browsing utilities, debugging tools,

and the C# compiler itself.

To be sure, metadata is the backbone of numerous .NET technologies

including remoting, reflection, late binding, XML web services, and object

serialization.

1.11 The Role Assembly Manifest

The .NET assembly also contains metadata that describes the assembly itself,

technically termed a manifest. Among other details, the manifest documents all

R.V.COLLEGE OF ENGINEERING Page 17

Page 18: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

external assemblies required by the current assembly to function correctly, the

assembly’s version number, copyrig ht information, and so on. Like type metadata,

it is always the job of the compiler to generate the assembly’s manifest. The

manifest documents the list of external assemblies required by *.exe(via

the .assembly extern directive) as well as various characteristics of the assembly

itself (version number, module name, and so on).

1.12 Compiling CIL to Platform-Specific Instructions

Since assemblies contain CIL instructions, rather than platform-specific instructions,

CIL code must be compiled before use. The entity that compiles CIL code into

meaningful CPU instructions is termed a just-in-time (JIT) compiler, which is also

known as Jitter. The .NET runtime environment forces a JIT compiler for each CPU

targeting the CLR, each of which is optimized for the platform it is targeting.

For example, if you are building a .NET application that is to be deployed to a

handheld device (such as a Pocket PC), the corresponding Jitter is well equipped to

run within a low-memory environment. On the other hand, if you are deploying your

assembly to a back-end server (where memory is seldom an issue), the Jitter will be

optimized to function in a high-memory environment. In this way, developers can

write a single body of code that can be efficiently JIT-compiled and executed on

machines with different architectures. Furthermore, as a given Jitter compiles CIL

instructions into corresponding machine code, it will cache the results in memory in

a manner suited to the target operating system. In this way, if a call is made to a

method named PrintDocument(), the CIL instructions are compiled into platform-

specific instructions on the first invocation and retained in memory for later use.

Therefore, the next time PrintDocument() is called, there is no need to recompile

the CIL.

R.V.COLLEGE OF ENGINEERING Page 18

Page 19: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

1.13 Summary

The point of this chapter was to lay out the conceptual framework necessary for

understanding the subject. We began by examining a number of limitations and

complexities found within the technologies prior to .NET and followed up with an

overview of how.NET and C# attempts to simplify the current state of affairs. The

CLR is able to host any .NET binary/assembly that abides by the rules of managed

code. As you have seen, assemblies contain CIL instructions (in addition to type

metadata and assembly manifest) that are compiled to platform-specific

instructions using a just-in-time (JIT) compiler.

1.14 Keywords Common Language Runtime (CLR)

Common Language Specification (CLS)

Common Type System (CTS)

Base Class Library (BCL)

Assemblies/Binaries

Common Intermediate Language (CIL)

Assembly Manifest

Type Metadata

Just-in-Time Compiler (Jitter)

1.15 Exercises

1. With a neat diagram, explain the basic building block of .NET framework.

2. What do you mean by BCL? Explain.

3. Bring out the important differences between single and multifile assemblies.

4. What are the key features of C#?

5. Briefly discuss the state of affairs that eventually led to the .NET platform. What is

the .NET solution and what C# brings to the table?

R.V.COLLEGE OF ENGINEERING Page 19

Page 20: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

6. Explain the concept of .NET binaries.

7. Explain the role of JIT compiler.

8. Explain the role of CIL and the benefits of CIL in .NET platform?

Module 1

Unit 2

CONTENTS:

1.16 Objectives2.2 Introduction2.3 Understanding the common type system2.4 Intrinsic CTS Data Types2.5 Understanding the Common Languages Specification2.6 Understanding the Common Language Runtime2.7 A tour of the .Net Namespaces2.8 Increasing Your Namespace Nomenclature 2.9 Deploying the .NET Runtime2.10 Summary2.11 Keywords2.12 Exercises

2.1 Objectives

R.V.COLLEGE OF ENGINEERING Page 20

Page 21: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

At the end of this lesson, the students will understand the following tasks in detail:

The Common Type System

CTS Data types

The Common Language Specification

The Common Language Runtime

Namespaces

2.2 Introduction

In the previous unit, we have seen the basic building blocks of .NET framework.

Here, we will elaborate each of these building blocks in detail. For the thorough

understanding of .NET framework and the languages that can be worked on the

framework, one should understand the concepts of CLR, CTS and CLS in detail.

2.3 Understanding the Common Type System

A given assembly may contain any number of distinct “types.”

In the world of .NET, “type” is simply a generic term used to refer to a

member from the set {class, structure, interface, enumeration, delegate}.

When you build solutions using a .NET-aware language, you will most likely

interact with each of these types.

For example, your assembly may define a single class that implements some

number of interfaces. Perhaps one of the interface methods takes an

enumeration type as an input parameter and returns a structure to the caller.

The Common Type System (CTS) is a formal specification that documents

how types must be defined in order to be hosted by the CLR.

Usually, the people who will be building tools and/or compilers that target the

.NET platform are concerned with the inner workings of the CTS.

However, for all .NET programmers it is important to learn about how to work

with the five types defined by the CTS in their language of choice.

R.V.COLLEGE OF ENGINEERING Page 21

Page 22: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Now, we will discuss the usage of five types defined by CTS.

CTS Class Types

Every .NET-aware language supports, the notion of a class type, which is the basis

of object-oriented programming (OOP). A class may be composed of any number of

members (such as properties, methods, and events) and data points. In C#, classes

are declared using the class keyword. For example,

// A C# class type

public class Calc

{

public int Add(int x, int y)

{

return x + y;

}

}

CTS allow a given class to support virtual and abstract members that define a

polymorphic interface for derived classes. But CTS classes may only derive from a

single base class (multiple inheritance is not allowed fro class).

Following table lists number of characteristics pertaining to class types.

Class Characteristic MeaningIs the class “sealed” or not?

Sealed classes cannot function as a base class to other classes.

Does the class implement any interfaces?

An interface is a collection of abstract members that provide a contract between the object and object user. The CTS allows a class to implement any number of interfaces.

R.V.COLLEGE OF ENGINEERING Page 22

Page 23: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Is the class abstract or concrete?

Abstract classes cannot be directly created, but are intended to define common behaviors for derived types. Concrete classes can be created directly.

What is the “visibility” of this class?

Each class must be configured with a visibility attribute. Basically, this feature defines if the class may be used by external assemblies, or only from within the defining assembly (e.g., a private helper class).

CTS Structure Types

The concept of a structure is also formalized under the CTS.

Structure is a user-defined type (UDT), which can be thought of as a

lightweight class type having value-based semantics.

CTS structures may define any number of parameterized constructors.

CTS structures are derived from a common base class: System.ValueType

This base class configures a type to behave as a stack-allocated entity rather

than a heap-allocated entity.

The CTS permits structures to implement any number of interfaces; but,

structures may not become a base type to any other classes or structures.

Therefore structures are explicitly sealed.

Typically, structures are best suited for modeling geometric and

mathematical data, and are created in C# using the struct keyword.

Consider an example:

// A C# structure type

struct Point

{

// Structures can contain fields.

public int xPos, yPos;

// Structures can contain parameterized constructors.

public Point(int x, int y)

{

xPos = x;

R.V.COLLEGE OF ENGINEERING Page 23

Page 24: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

yPos = y;

}

// Structures may define methods.

public void Display()

{

Console.WriteLine("({0}, {1})", xPos, yPos);

}

}

CTS Interface Types

Interfaces are nothing more than a named collection of abstract member

definitions, which may be supported (i.e., implemented) by a given class or

structure.

Interfaces are the only .NET type that does not derive from a common base

type.

This indicates that interfaces are pure protocol and do not provide any

implementation.

On their own, interfaces are of little use. However, when a class or structure

implements a given interface, you are able to request access to the supplied

functionality using an interface reference in a polymorphic manner.

When you create custom interfaces using a .NET aware programming

language, the CTS permits a given interface to derive from multiple base

interfaces.

This allows to build some interesting behaviors.

In C#, interface types are defined using the interface keyword, for example:

// A C# interface type.

public interface IDraw

R.V.COLLEGE OF ENGINEERING Page 24

Page 25: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

{

void Draw();

}

CTS Enumeration Types

Enumerations are a handy programming construct that allows you to group

name/value pairs under a specific name.

By default, the storage used to hold each item within enumeration type is a

32-bit integer (System.Int32).

However, it is possible to alter this storage slot if needed (e.g., when

programming for a low-memory device such as a Pocket PC).

The CTS demands that enumerated types derive from a common base class,

System.Enum. This base class defines a number of interesting members that

allow you to extract, manipulate, and transform the underlying name/value

pairs programmatically.

In C#, enumerations are defined using the keyword enum.

Consider an example of creating a video-game application that allows the player to

select one of three character categories (Wizard, Fighter, or Thief). Rather than

keeping track of raw numerical values to represent each possibility, you could build

a custom enumeration as:

// A C# enumeration type

public enum CharacterType

{

Wizard = 100,

Fighter = 200,

Thief = 300

}

CTS Delegate Types

R.V.COLLEGE OF ENGINEERING Page 25

Page 26: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Delegates are the .NET equivalent of a type-safe C-style function pointer.

The key difference is that a .NET delegate is a class that derives from

System.MulticastDelegate, rather than a simple pointer to a raw memory

address.

Delegates are useful when you wish to provide a way for one entity to

forward a call to another entity.

Delegates provide intrinsic support for multicasting, i.e. forwarding a request

to multiple recipients.

They also provide asynchronous method invocations.

They provide the foundation for the .NET event architecture.

. In C#, delegates are declared using the delegate keyword as shown in the

following example:

// This C# delegate type can 'point to' any method

// returning an integer and taking two integers as input.

public delegate int BinaryOp(int x, int y);

CTS Type Members

We have seen till now that most types in CTS can take any number of members.

Formally speaking, a type member is constrained by the set {constructor,

finalizer, static constructor, nested type, operator, method, property, indexer, field,

read only field, constant, event}. The CTS defines various “adornments” that may

be associated with a given member. For example, each member has a given

visibility feature (e.g., public, private, protected). Some members may be declared

as abstract to enforce a polymorphic behavior on derived types as well as virtual to

define a canned (but overridable) implementation. Also, most members may be

configured as static (bound at the class level) or instance (bound at the object

level). The construction of type members is examined later in detail.

2.4 Intrinsic CTS Data Types

R.V.COLLEGE OF ENGINEERING Page 26

Page 27: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

CTS provide a well-defined set of intrinsic data types used by all .NET aware

languages. Although a given language typically has a unique keyword used to

declare an intrinsic CTS data type, all language keywords ultimately resolve to the

same type defined in an assembly named mscorlib.dll.

Following table lists how key CTS data types are expressed in various .NET

languages.

.NET Base Type (CTS Data Type)

VB.NET Keyword C# Keyword Managed Extensions for C+

+ KeywordSystem.Byte Byte byte unsigned char

System.SByte SByte sbyte signed charSystem.Int16 Short short shortSystem.Int32 Integer int int or longSystem.Int64 Long long __int64

System.UInt16 UShort ushort unsigned shortSystem.UInt32 UInteger uint unsigned int or

unsigned longSystem.UInt64 ULong ulong unsigned __int64

System.Single Single float FloatSystem.Double Double double DoubleSystem.Object Object object Object^System.Char Char char wchar_t

System.String String string String^System.Decimal Decimal decimal DecimalSystem.Boolean Boolean bool Bool

2.5 Understanding Common Language Specification

We know that, different languages express the same programming constructs in

unique, language specific terms. For example, in C# you denote string

R.V.COLLEGE OF ENGINEERING Page 27

Page 28: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

concatenation using the plus operator (+), while in VB .NET we use the ampersand

(&). Even when two distinct languages express the same programmatic idiom (e.g.,

a function with no return value), the chances are very good that the syntax will

appear quite different on the surface:

' VB .NET method returning nothing.

Public Sub MyMethod()

' Some code...

End Sub

// C# method returning nothing.

public void MyMethod()

{

// Some code...

}

Since the respective compilers (like vbc.exe and csc.exe) produce similar CIL

instructions, the variation in syntax is minor for .NET runtime. However, languages

can also differ with regard to their overall level of functionality. For example, C#

may allow to overload some type of operator which VB.NET may not. Given these

possible variations, it would be ideal to have a baseline to which all .NET-aware

languages are expected to conform.

The Common Language Specification (CLS) is a set of rules that describe the small

and complete set of features. These features are supported by a .NET-aware

compiler to produce a code that can be hosted by CLR. Also, this code can be

accessed by all languages in the .NET platform.

R.V.COLLEGE OF ENGINEERING Page 28

Page 29: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

In many ways, the CLS can be viewed as a subset of the full functionality defined by

the CTS. The CLS is ultimately a set of rules that compiler builders must follow, if

they plan their products to function properly within the .NET universe. Each rule

describes how this rule affects those who build the compilers as well as those who

interact with them. For example, the CLS Rule 1 says:

Rule 1: CLS rules apply only to those parts of a type that are exposed outside the

defining assembly.

Given this rule, we can understand that the remaining rules of the CLS do not apply

to the logic used to build the inner workings of a .NET type. The only aspects of a

type that must match to the CLS are the member definitions themselves (i.e.,

naming conventions, parameters, and return types). The implementation logic for a

member may use any number of non-CLS techniques, as the outside world won’t

know the difference.

To illustrate, the following Add() method is not CLS-compliant, as the parameters

and return values make use of unsigned data (which is not a requirement of the

CLS):

public class Calc

{

// Exposed unsigned data is not CLS compliant!

public ulong Add(ulong x, ulong y)

{

return x + y;

}

R.V.COLLEGE OF ENGINEERING Page 29

Page 30: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

}

We can make use of unsigned data internally as follows:

public class Calc

{

public int Add(int x, int y)

{

// As this ulong variable is only used internally,

// we are still CLS compliant.

ulong temp;

temp= x+y;

return temp;

}

}

Now, we have a match to the rules of the CLS, and can assured that all .NET

languages are able to invoke the Add() method.

In addition to Rule 1, the CLS defines numerous other rules. For example, the CLS

describes how a given language must represent text strings, how enumerations

should be represented internally (the base type used for storage), how to define

static members, and so on. But the internal understanding of the CTS and CLS

specifications is for tool/compiler builders.

Ensuring CLS Compliance

R.V.COLLEGE OF ENGINEERING Page 30

Page 31: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

C# does define a number of programming constructs that are not CLS-compliant.

But, we can instruct the C# compiler to check the code for CLS compliance using a

single .NET attribute:

// Tell the C# compiler to check for CLS compliance.

[assembly: System.CLSCompliant(true)]

This statement must be placed outside the scope of any namespace. The

[CLSCompliant] attribute will instruct the C# compiler to check each and every line

of code against the rules of the CLS. If any CLS violations are discovered, we will

receive a compiler error and a description of the offending code.

2.6 Understanding Common Language Runtime

Programmatically speaking, the term runtime can be understood as a collection of

external services that are required to execute a given compiled unit of code. For

example, when developers make use of the Microsoft Foundation Classes (MFC) to

create a new application, they are aware that their program requires the MFC

runtime library (i.e., mfc42.dll). Other popular languages also have a corresponding

runtime. VB6 programmers are also tied to a runtime module (e.g., msvbvm60.dll).

Java developers are tied to the Java Virtual Machine (JVM) and so on.

The .NET platform offers a runtime system, which can be described as follows:

The key difference between the .NET runtime and the various other runtimes is

that the .NET runtime provides a single well-defined runtime layer that is shared

by all languages and platforms that are .NET-aware.

R.V.COLLEGE OF ENGINEERING Page 31

Page 32: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

The root of the CLR is physically represented by a library named mscoree.dll

(Common Object Runtime Execution Engine).

When an assembly is referenced for use, mscoree.dll is loaded automatically,

which in turn loads the required assembly into memory.

The runtime engine is responsible for a number of tasks.

First and foremost, it is the entity in-charge of resolving the location of an

assembly and finding the requested type within the binary by reading the

contained metadata.

The CLR then lays out the type in memory, compiles the associated CIL into

platform-specific instructions, performs any necessary security checks, and then

executes the code in question.

In addition to loading your custom assemblies and creating your custom types,

the CLR will also interact with the types contained within the .NET base class

libraries when required.

Although the entire base class library has been broken into a number of discrete

assemblies, the key assembly is mscorlib.dll. The mscorlib.dll contains a large

number of core types that encapsulate a wide variety of common programming

tasks as well as the core data types used by all .NET languages. When you

build .NET solutions, you automatically have access to this particular assembly.

Figure 2.1 illustrates the workflow that takes place between the source code (which

is making use of base class library types), a given .NET compiler, and the .NET

execution engine.

R.V.COLLEGE OF ENGINEERING Page 32

Page 33: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

R.V.COLLEGE OF ENGINEERING Page 33

.NET source code written

in some .NET-

aware Language

Base Class Libraries

(mscorlib.dll and so on)

Some .NET compiler

DLL or EXE Assembly

(CIL, Metadata and Manifest)

.NET Execution Engine (mscoree.dll)

Class Loader

Jitter

Platform-Specific

Instructions

Execute the application

Page 34: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Figure 2.1 mscoree.dll in action

2.7 A Tour of the .NET Namespaces

Unlike C, C++ and Java, the C# language does not provide any language-specific

code library. Instead, C# provides the language-neutral .NET libraries. To keep all

the types within the base class libraries, the .NET platform makes extensive use of

the namespace concept. A namespace is a grouping of related types contained in

an assembly. In other words, namespace is a way to group semantically related

types (classes, enumerations, interfaces, delegates and structures) under a single

umbrella. For example, the System.IO namespace contains file I/O related types, the

System.Data namespace defines basic database types, and so on. It is very

R.V.COLLEGE OF ENGINEERING Page 34

Page 35: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

important to point out that a single assembly (such as mscorlib.dll) can contain any

number of namespaces, each of which can contain any number of types.

The advantage of having namespaces is that, any language targeting the .NET

runtime makes use of same namespaces and same types as a C# developer. For

example, consider following programs written in C#, VB.NET and MC++.

// C# code

using System;

public class Test

{

public static void Main()

{

Console.WrtieLine(“Hello World”);

}

}

// VB.NET code

Imports System

Public Module Test

Sub Main()

Console.WrtieLine(“Hello World”)

End Sub

End Module

// MC++ code

R.V.COLLEGE OF ENGINEERING Page 35

Page 36: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

#using <mscorlib.dll>

using namespace System;

void Main()

{

Console::WrtieLine(“Hello World”);

}

Note that each language is making use of Console class defined in the System

namespace. Apart from minor syntactic variations, three programs look very similar,

both physically and logically.

There are numerous base class namespaces within .NET. The most fundamental

namespace is System. The System namespace provides a core body of types that

the programmer need to control time. In fact, one cannot build any sort of

functional C# application without at least making a reference to the System

namespace. Following table shows some of the namespaces:

.NET Namespace MeaningSystem System contains numerous useful types dealing with

intrinsic data, mathematical computations, random number generation, environment variables, and garbage collection, as well as a number of commonly used exceptions and attributes.

System.Collections These namespaces define a number of stock container objects

System.Collections.Generic (ArrayList, Queue etc), as well as base types and interfaces that allow you to build customized collections. As of .NET 2.0, the collection types have been extended with generic capabilities.

System.DataSystem.Data.OdbcSystem.Data.OracleClientSystem.Data.OleDbSystem.Data.SqlClient

These namespaces are used for interacting with databases using ADO.NET.

System.Diagnostics Here, you find numerous types that can be used to

R.V.COLLEGE OF ENGINEERING Page 36

Page 37: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

programmatically debug and trace your source code.System.DrawingSystem.Drawing.Drawing2DSystem.Drawing.Printing

Here, you find numerous types wrapping graphical primitives such as bitmaps, fonts, and icons, as well as printing capabilities.

System.IOSystem.IO.CompressionSystem.IO.Ports

These namespaces include file I/O, buffering, and so forth. As of .NET 2.0, the IO namespaces now include support compression and port manipulation.

System.Net This namespace (as well as other related namespaces) contains types related to network programming (requests/responses, sockets, end points, and so on).

System.ReflectionSystem.Reflection.Emit

These namespaces define types that support runtime type discovery as well as dynamic creation of types.

System.Runtime.InteropServices This namespace provides facilities to allow .NET types to interact with “unmanaged code” (e.g., C-based DLLs and COM servers) and vice versa.

System.Runtime.Remoting

This namespace (among others) defines types used to build solutions that incorporate the .NET remoting layer.

System.Security Security is an integrated aspect of the .NET universe. In the security-centric namespaces you find numerous types dealing with permissions, cryptography, and so on.

System.Threading This namespace defines types used to build multithreaded applications.

System.Web A number of namespaces are specifically geared toward the development of .NET web applications, including ASP.NET and XML web services.

System.Windows.Forms This namespace contains types that facilitate the construction of traditional desktop GUI applications.

System.Xml The XML-centric namespaces contain numerous types used to interact with XML data.

Accessing a Namespace Programmatically

A namespace is a convenient way to logically understand and organize related

types. Consider the System namespace. From programmer’s perspective,

System.Console represents a class named Console that is contained within a

namespace called System. However, in the eyes of the .NET runtime, it is a single

entity named System.Console.

In C#, the using keyword simplifies the process of referencing types defined in a

particular namespace. In a traditional desktop application, we can include any

number of namespaces like –

R.V.COLLEGE OF ENGINEERING Page 37

Page 38: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

using System; // General base class library types.

using System.Drawing; // Graphical rendering types.

Once we specify a namespace, we can create instances of the types they contain.

For example, if we are interested in creating an instance of the Bitmap class, we

can write:

using System;

using System.Drawing;

class MyApp

{

public void DisplayLogo()

{

// create a 20x20 pixel bitmap.

Bitmap bm = new Bitmap(20, 20);

...

}

}

As this application is referencing System.Drawing, the compiler is able to resolve

the Bitmap class as a member of this namespace. If we do not specify the

System.Drawing namespace, we will get a compiler error. However, we can declare

variables using a fully qualified name as well:

using System;

class MyApp

{

R.V.COLLEGE OF ENGINEERING Page 38

Page 39: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

public void DisplayLogo()

{

// Using fully qualified name.

System.Drawing.Bitmap bm =new System.Drawing.Bitmap(20, 20);

...

}

}

Remember that both the approaches (a short-hand method with using and making

use of fully qualified name) results in the exact same underlying CIL and has no

effect on performance or the size of the assembly.

2.8 Increasing Your Namespace Nomenclature

There are thousands of namespaces in .NET framework. But what makes a

namespace unique is that the types it defines are all somehow semantically related.

So, depending on our requirement, we can make use of only required namespaces.

For example, if we are building console applications, then we need not worry about

System.Windows.Forms and System.Drawing namespaces. To know more about

specific namespaces, we can use any one of the following:

.NET SDK online documentation (MSDN – Microsoft Developer Network)

The ildasm.exe utility

R.V.COLLEGE OF ENGINEERING Page 39

Page 40: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

The Class Viewer Web application

The wincv.exe desktop application

The Visual Studio.NET integrated Object Browser

2.9 Deploying the .NET Runtime

The .NET assemblies can be executed only on a machine that has the .NET

Framework installed. As an individual who builds .NET software, this should never

be an issue, as your development machine will be properly configured at the time

you install the freely available .NET Framework 2.0 SDK or a commercial .NET

development environments such as Visual Studio 2005.

But, we can not copy and run a .NET application in a computer in which .NET is not

installed. However, if you deploy an assembly to a computer that does not

have .NET installed, it will fail to run. For this reason, Microsoft provides a setup

package named dotnetfx.exe that can be freely shipped and installed along with

your custom software. This installation program is included with the .NET

Framework 2.0 SDK, and it is also freely downloadable from www.microsoft.com.

Once dotnetfx.exe is installed, the target machine will now contain the .NET base

class libraries, .NET runtime (mscoree.dll), and additional .NET infrastructure (such

as the GAC, Global Assembly Cashe).

Note that if you are building a .NET web application, the end user’s machine does

not need to be configured with the .NET Framework, as the browser will simply

receive generic HTML and possibly client-side JavaScript.

2.10 Summary

R.V.COLLEGE OF ENGINEERING Page 40

Page 41: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

In this Unit, we have explored the CTS, CLR and CLS in detail. We have examined a

number of tools that allow you to check out the types within a given .NET

namespace. We wrapped up with a brief examination of the process of configuring a

given machine to host the .NET runtime. With this necessary preamble complete,

you can now begin to build .NET assemblies using C#.

2.11 Keywords Structure Enumeration Class Interface Delegate Microsoft Common Object Runtime Execution Engine (mscoree) Namespaces using

2.12 Exercises

1. What are namespaces? List and explain the purpose of at least five namespaces.

2. Explain with a neat diagram, the workflow that takes place between your source code, a

given .NET complier and the .NET execution engine.

3. Explain common type system in detail.

4. What are basic CTS data types? Explain.

Module 1

Unit 3

CONTENTS:

1.17 Objectives

R.V.COLLEGE OF ENGINEERING Page 41

Page 42: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

3.2 Introduction

3.3Role of Command Line Compiler (csc.exe)

3.4Building C# Applications using csc.exe

3.5Working with csc.exe Response Files

3.6Generating Bug Reports

3.7Remaining C# Compiler Options

3.8The Command Line Debugger (cordbg.exe)

3.9Using the Visual Studio.NET IDE

3.10 The C# “Pre-processor” Directives

3.11 An Interesting Aside: System.Environment Class

3.12 Summary

3.13 Keywords

3.14 Exercises

3.1 Objectives

At the end of this lesson, the students will understand the following tasks in detail:

The Role of Command Line Compiler

Building Applications using csc.exe

Response files

Bug Reports

Compiler Options

Command Line Debugger

3.2 Introduction

R.V.COLLEGE OF ENGINEERING Page 42

Page 43: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

C# is one of many possible languages which may be hosted by Visual Studio.NET

(VS.NET). Unlike previous editions of Microsoft IDEs (Integrated Development

Environments), the professional and enterprise versions of VS.NET may be used to

build various types of projects like C#, J#, VB.NET, MC++ and so on. In this unit, we

will examine raw C# compiler. We will see how to set up environment variables to

run C# applications using command line compiler, how to generate bug reports,

how to generate response files, what are preprocessor directives and so on. This

unit also offers a grand tour of the key features of the VS.NET IDE within the context

of C#.

3.3 The Role of Command Line Compiler (csc.exe)

There are a number of techniques to compile C# source code. One way is to use the

C# command-line compiler, csc.exe (where csc stands for C-Sharp Compiler). This

tool is included with the .NET Framework 2.0 SDK. Though we may not build a large-

scale application using the command-line compiler, it is important to understand

the basics of how to compile *.cs files by hand. Few reasons for having a grip on the

process are:

The most obvious reason is the simple fact that one may not have a copy of

Visual Studio 2005. But only free .NET SDK.

One may plan to make use of automated build tools such as MSBuild or NAnt.

One may want to understand C# deeply. When you use graphical IDEs to

build applications, you are ultimately instructing csc.exe how to manipulate

your C# input files. In this light, it is better to see what takes place behind

the scenes.

Another benefit of working with csc.exe is that you become that much more

comfortable in manipulating other command-line tools included with the .NET

Framework 2.0 SDK. Moreover, a number of important utilities are accessible

only from the command line.

R.V.COLLEGE OF ENGINEERING Page 43

Page 44: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Configuring the C# Command-Line Compiler

Before starting the C# command-line compiler, we need to ensure that our

development machine recognizes the existence of csc.exe. If the machine is not

configured correctly, we have to specify the full path to the directory containing

csc.exe before compiling C# files. We have to set the path by following the steps:

1. Right-click the My Computer icon and select Properties from the pop-up

menu.

2. Select the Advanced tab and click the Environment Variables button.

3. Double-click the Path variable from the System Variables list box.

4. Add the following line to the end of the current Path value:

C:\Windows\Microsoft.NET\Framework\v2.0.50215

Note that, the above line may not be exactly the same in every computer. We must

enter the current version and location of .NET Framework SDK. To check whether

the setting has been done properly or not, open a command prompt and type

csc -? Or csc /?

If settings were correct, we will see a list of options supported by the C# compiler.

Configuring Additional .NET Command-Line Tools

We have to set Path variable with one more line as

C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\Bin

This directory contains additional command-line tools that are commonly used

during .NET development. With these two paths established, we will be able to run

any .NET utility from any command window. To confirm this new setting, enter the

R.V.COLLEGE OF ENGINEERING Page 44

Page 45: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

following command in a command prompt to view the options of the GAC (global

assembly cashe) utility, gacutil.exe:

gacutil -?

Note that the above explained method is to compile the C# program in any command prompt. In

stead of that, we can directly use the SDK in the Visual Studio Tools menu.

3.4 Building C# Applications Using csc.exe

To build a simple C# application, open a notepad and type the following code:

// A simple C# application.

using System;class Test{

public static void Main(){

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

}

Now, save this file in any convenient location as Test.cs. Now, we have to provide

the option for which type of output file we want. The options for output are given in

the following table:

File Output Option

Meaning

/out This option is used to specify the name of the assembly to be

R.V.COLLEGE OF ENGINEERING Page 45

Page 46: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

created. By default, the assembly name is the same as the name of the initial input *.cs -file (in the case of a *.dll) or the name of the type containing the program’s Main() method (in the case of an *.exe).

/target:exe This option builds an executable console application. This is the default file output type, and thus may be omitted when building this application type.

/target:library This option builds a single-file *.dll assembly./target:module This option builds a module.Modules are elements of multifile

assemblies./target:winexe Although you are free to build Windows-based applications using

the /target:exe flag, the /target:winexe flag prevents a console window from appearing in the background.

To compile TestApp.cs, use the command:

csc /target:exe Test.cs

Most of the C# compilers support an abbreviated version, such as /t rather than

/target. Moreover, /target is a default option. So, we can give simply,

csc Test.cs

Now an exe file will be created with the name Test.exe. Now the program can be

run by typing –

Test.exe

at the command prompt.

Referencing External Assemblies

Here we will see how to compile an application that makes use of types defined in a

separate .NET assembly. Note that mscorlib.dll is automatically referenced during

the compilation process. To illustrate the process of referencing external

assemblies, consider an example –

using System;

using System.Windows.Forms;

R.V.COLLEGE OF ENGINEERING Page 46

Page 47: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

class Test

{

public static void Main()

{

MessageBox.Show("Hello...");

}

}

Since we have made use of the MessageBox class, we must specify the

System.Windows.Forms.dll assembly using the /reference flag which can be

abbreviated to /r as –

csc /r:System.Windows.Forms.dll Test.cs

Now, running the application will give the output as –

Compiling Multiple Source Files with csc.exe

When we have more than one *.cs source file, then we can compile them together.

For illustration, consider the following example –

File Name: MyTest.cs

R.V.COLLEGE OF ENGINEERING Page 47

Page 48: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

using System;

using System.Windows.Forms;

class MyTest

{

public void display()

{

MessageBox.Show("Hello...");

}

}

File Name: Test.cs

using System;

class Test

{

public static void Main()

{

MyTest t = new MyTest ();

t.display();

}

}

We can compile C# files by listing each input file explicitly:

csc /r:System.Windows.Forms.dll Test.cs MyTest.cs

R.V.COLLEGE OF ENGINEERING Page 48

Page 49: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

As an alternative, the C# compiler allows you to make use of the wildcard character

(*) to inform csc.exe to include all *.cs files contained in the project directory:

csc /r:System.Windows.Forms.dll *.cs

Referencing Multiple External Assemblies

If we want to reference numerous external assemblies, then we can use a

semicolon-delimited list. For example:

csc /r:System.Windows.Forms.dll; System.Drawing.dll *.cs

3.5 Working with csc.exe Response Files

When we are building complex C# applications, we may need to use several flags

that specify numerous referenced assemblies and *.cs input files. To reduce the

burden of typing those flags every time, the C# compiler provides response files.

C# response files contain all the instructions to be used during the compilation of a

program. These files end in a *.rsp (response) extension.

Consider the following file, which is a response file for the example Test.cs

discussed in the previous section.

# This is the response file for the Test.exe app

# External assembly references.

/r:System.Windows.Forms.dll

R.V.COLLEGE OF ENGINEERING Page 49

Page 50: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

# output and files to compile (using wildcard syntax).

/target:exe /out:Test.exe *.cs

Note that # symbol is used for comment line. If we have saved this file in the same

directory as the C# source code files to be compiled, we have to use following

command to run the program.

csc @Test.rsp

If needed, we can specify multiple *.rsp files as input (e.g., csc @FirstFile.rsp

@SecondFile.rsp @ThirdFile.rsp). In case of multiple response files, the compiler

processes the command options as they are encountered. Therefore, command-line

arguments in a latter *.rsp file can override options in a previous response file.

Also note that flags listed explicitly on the command line before a response file will

be overridden by the specified *.rsp file. Thus, if we use the statement,

csc /out:MyCoolApp.exe @Test.rsp

the name of the assembly would still be Test.exe (rather than MyCoolApp.exe),

given the /out:Test.exe flag listed in the Test.rsp response file. However, if we list

flags after a response file, the flag will override settings in the response file.

Note The /reference flag is cumulative. Regardless of where you specify external

assemblies (before, after, or within a response file) the end result is a summation of

each reference assembly.

R.V.COLLEGE OF ENGINEERING Page 50

Page 51: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

The Default Response File (csc.rsp)

C# compiler has an associated default response file (csc.rsp), which is located in

the same directory as csc.exe itself (e.g., C:\Windows\Microsoft.NET\Framework\

v2.0.50215). If we open this file using Notepad, we can see that numerous .NET

assemblies have already been specified using the /r: flag. When we are building our

C# programs using csc.exe, this file will be automatically referenced, even if we

provide a custom *.rsp file. Because of default response file, the current Test.exe

application could be successfully compiled using the following command set

csc /out:Test.exe *.cs

If we wish to disable the automatic reading of csc.rsp, we can specify the /noconfig

option:

csc @Test.rsp /noconfig

3.6 Generating Bug Reports

The C# compiler provides a flag named /bugreport to specify a file that will be

populated by csc.exe with various statistics regarding current build; including any

errors encountered during the compilation. The syntax for using this flag is–

csc /bugreport:bugs.txt *.cs

We can enter any corrective information for possible errors in the program, which

will be saved to the specified file. For example, consider the program –

using System;

R.V.COLLEGE OF ENGINEERING Page 51

Page 52: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

class Test

{

public static void Main()

{

Console.WriteLine(“Hello”) //note that ; is not given

}

}

When we compile this file using /bugreport flag, the error message will be displayed

and corrective action is expected as shown –

Test.cs (23, 11): Error CS1002: ; expected

-----------------

Please describe the compiler problem: _

Now if we enter the statement like

FORGOT TO TYPE SEMICOLON

then, the same will be stored in the bugs.txt file.

3.7 Remaining C# Compiler Options

C# compiler has many flags that can be used to control how the .NET assembly to

be generated. Following table lists some of the flags and their meaning.

Command Line flags of csc.exe

Meaning

R.V.COLLEGE OF ENGINEERING Page 52

Page 53: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

@ Allows to specify a response file used during compilation/? Or /help Prints the list of all command line flags of csc.exe/addmodule Used to specify the modules to add to a multifile assembly/baseaddress Used to specify the preferred base address at which to load a *.dll/bugreport Used to build text-based bug reports for the current compilation/checked Used to specify whether integer arithmetic that overflows the

bounds of the data type will cause an exception at run time/codepage Used to specify the code page to use for all source code files in

the compilation/debug Forces csc.exe to emit debugging information/define Used to define preprocessor symbols/doc Used to construct an XML documentation file/filealign Specifies the size of sections in the output file/fullpaths Specifies the absolute path to the file in compiler output/incremental Enables incremental compilation of source code files/lib Specifies the location of assemblies referenced via /reference/linkresource Used to create a link to a managed resource/main Specifies which Main() method to use as the program’s entry point

if multiple Main() methods have been defined in the current *.cs file set.

/nologo Suppresses compiler banner information when compiling the file/nostdlib Prevents the automatic importing of the core .NET library,

mscorlib.dll/noconfig Prevents the use of *.rsp files during the current compilation/nowarn Suppress the compiler’s ability to generate specified warnings/optimize Enable or disable optimization/out Specifies the name of the output file/recurse Searches subdirectories for source files to compile /reference Used to reference an external assembly/resource Used to embed .NET resources into the resulting assembly/target Specifies the format of the output file./unsafe Compiles code that uses the C# “unsafe” keyword/utf8output Displays compiler output using UTF-8 encoding/warn Used to sent warning level for the compilation cycle/warnaserror Used to automatically promote warnings to errors/win32icon Inserts an .ico file into the output file/win32res Inserts a Win32.resource into the output file

3.8 The Command-Line Debugger (cordbg.exe)

R.V.COLLEGE OF ENGINEERING Page 53

Page 54: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

The .NET Framework SDK provides a command-line debugger named cordbg.exe.

This tool provides dozens of options that allow you to debug your assembly. You

may view them by specifying the /? flag:

cordbg /?

Following table lists some of the flags recognized by cordbg.exe (with the

alternative shorthand notation) once you have entered a debugging session.

Command Line Flag of cordbg.exe

Meaning

b[reak] Set or display current breakpoints.del[ete] Remove one or more breakpoints.ex[it] Exit the debuggerg[o] Continue debugging the current process until hitting next

breakpoint.o[ut] Step out of the current function.p[rint] Print all loaded variables (local, arguments, etc.).Si Step into the next line.So Step over the next line.

Usually, we will make use of the VS.NET integrated debugger. Hence, the

cordbg.exe is rarely used in reality.

Debugging at the Command Line

Before you can debug your application using cordbg.exe, the first step is to

generate debugging symbols for your current application by specifying the /debug

flag of csc.exe. For example, to generate debugging data for TestApp.exe, enter the

following command set:

csc @testapp.rsp /debug

R.V.COLLEGE OF ENGINEERING Page 54

Page 55: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

This generates a new file named testapp.pdb. If you do not have an associated

*.pdb file, it is still possible to make use of cordbg.exe; however, you will not be

able to view your C# source code during the process (which is typically no fun

whatsoever, unless you wish to complicate matters by reading CIL code). Once you

have generated a *.pdb file, open a session with cordbg.exe by specifying your .NET

assembly as a command-line argument (the *.pdb file will be loaded automatically):

cordbg.exe testapp.exe

At this point, you are in debugging mode and may apply any number of cordbg.exe

flags at the (cordbg) command prompt.

3.9 Using the Visual Studio .NET IDE

Till now, we have discussed how to compile C# programs in command prompt.

Visual Studio .NET provides an IDE (Integrated Development Environment) to build

applications using any number of .NET-aware languages like C#, VB.NET, J#, MFC

etc. Here, we will examine some of the core features of VS.NET IDE.

The VS .NET Start Page

When we launch VS .NET, we can see start page as –

R.V.COLLEGE OF ENGINEERING Page 55

Page 56: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

This will provide an option to open existing projects or to create new projects.

Creating a VS .NET Project Solution

Once we opt for creating new project, then, we can see the following window:

R.V.COLLEGE OF ENGINEERING Page 56

Page 57: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

This window will allow us to choose the language (C#, VB.NET etc), then type of the

application (windows, console etc). Then we can provide the name of the

application and the location where the application to be stored. Following is a list of

project types provided by C#.

Project Type MeaningWindows Application Represents Windows Form applicationClass Library Used to build a single file assembly (*.dll)Windows Control Library Allows to build a single file assembly (*.dll) that

contains custom Windows Forms Controls. (ActiveX controls)

ASP.NET Web Application Used to build a web applicationASP.NET Web Service Used to build a .NET Web Service. Web Service is a

block of code, reachable using HTTP requests.Web Control Library Used to build customized Web controls. These GUI

widgets are responsible for emitting HTML to a requesting browser.

Console Application Just like command window. Windows Services Used to build NT/2000 services. Services are

background worker applications that are launched during OS boot process.

R.V.COLLEGE OF ENGINEERING Page 57

Page 58: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

3.10 C# Preprocessor Directives

Like C and C++, C# provides various symbols to interact with the compilation

process. But, the term preprocessor doesn’t exactly mean what it implies in C or C+

+. There is no separate preprocessing step in C#. Rather, preprocessor directives

are processed as a part of the lexical analysis phase of the compiler. However, the

syntax of C# preprocessor is similar to that of C and C++. Following is a list of

preprocessors supported by C#.

C# Preprocessor Symbol Meaning#define, #undef Used to define and un-define conditional compilation

symbol.#if, #elif, #else, #endif Used to conditionally skip sections of source code.#line Used to control the line numbers emitted for errors and

warnings#error, #warning Used to issue errors and warnings for the current build#region, #endregion Used to explicitly mark sections of source code. Under

VS.NET, regions may be expanded and collapsed within the code window. Other IDEs (including text editors) will ignore these symbols.

Specifying Code Regions

Using #region and #endregion tags, we can specify a block of code that may be

hidden from view and identified by a textual marker. The use of regions helps to

keep lengthy *.cs files more manageable. For example, we can create a region for

defining a type’s constructor (may be class, structure etc), type’s properties and so

on.

Consider the following code:

class Test

R.V.COLLEGE OF ENGINEERING Page 58

Page 59: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

{

…….

#region Unwanted

public class sub1

{

…….

}

public interface sub2

{

…………

}

#endregion

}

Now, when we put mouse curser on that region, it will be shown as –

R.V.COLLEGE OF ENGINEERING Page 59

Page 60: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Conditional Code Compilation:

The preprocessor directives #if, #elif, #else and #endif allows to conditionally

compile a block of code based on predefined symbols. Consider the following

example –

#define MAX

using System;

class Test

{

R.V.COLLEGE OF ENGINEERING Page 60

Page 61: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

public static void Main()

{

#if(MAX)

Console.WriteLine("MAX is defined");

#else

Console.WriteLine("MAX is not defined");

#endif

}

}

The output will be: MAX is defined

Issuing Warnings and Errors:

The #warning and #error directives allows to instruct the C# compiler to generate

a warning or error. For example, we wish to issue a warning when a symbol is

defined in the current project. This is helpful when a big project is handled by many

people. Consider the following code:

#define MAX

using System;

class Test

{

public static void Main()

{

#if(MAX)

R.V.COLLEGE OF ENGINEERING Page 61

Page 62: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

#warning MAX is defined by me!!!

………..

#endif

}

}

When we compile, the program will give warning message –

Test.cs(7,21): warning CS1030: #warning: 'MAX is defined by me!!!'

Altering Line Numbers:

The directive #line is rarely used in any project. This directive allows to alter the

compiler’s recognition of #line numbers during its recording of compilation

warnings and errors. To reset the default line numbering, we can specify default

tag. Consider the following code:

#define MAX

using System;

class Test

{

public static void Main()

{

#line 300 //next line will take the number 300

#warning MAX is defined by me!!!

………..

#line default// default numbering will continue

}

}

R.V.COLLEGE OF ENGINEERING Page 62

Page 63: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

When we compile, the program will give warning message –

Test.cs(300,21): warning CS1030: #warning: 'MAX is defined by me!!!'

Note that the line number appeared as 300, though the actual line was 7.

3.11 An Interesting Aside: The System.Environment Class

The System.Environment class allows to obtain a number of details regarding the

context of the operating system hosting .NET application by using various static

members. Consider the following example –

using System;

class Test

{

public static void Main(string[] args)

{

Console.WriteLine("OS: {0}", Environment.OSVersion);

Console.WriteLine("Current Directory: {0}",

Environment.CurrentDirectory);

string[] s = Environment.GetLogicalDrives();

for(int i=0;i<s.Length;i++)

R.V.COLLEGE OF ENGINEERING Page 63

Page 64: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Console.WriteLine("Drive {0}: {1} ", i, s[i]);

Console.WriteLine("Version of .NET: {0}", Environment.Version);

}

}

The Output will be (depending on OS and version of .NET, it may vary) –

OS: Microsoft Windows NT 5.1.2600 Service Pack 3

Current Directory: C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0

Drive 0: A:\

Drive 1: C:\

Drive 2: D:\

Drive 3: E:\

Drive 4: F:\

Version of .NET: 2.0.50727.3082

3.12 Summary

The point of this chapter was to introduce you to the process of building C#

applications. As you have seen, the ultimate recipient of your *.cs files is the C#

compiler, csc.exe. You have learnt how to use csc.exe in the raw and during the

process, you examined a number of compiler options including error reporting/bug

report, response files etc. You have also explored the key details of the VS.NET IDE.

Truly speaking, VS.NET IDE is nothing more than an elaborate wrapper around the

raw C# compiler. That is, anything that can be done with VS.NET can be done with

the raw C# compiler too.

R.V.COLLEGE OF ENGINEERING Page 64

Page 65: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

3.13 Keywords

csc.exe

Response Files

Global Assembly Cache (GAC)

gacutil.exe

Bug Reports

Command Line debugger or cordbg.exe

Preprocessor Directives

#define, #undef

#line

#region, #endregion

#if, #elif, #endif, #else

#error, #warning

System.Environment Class

3.14 Exercises

1. Explain the role of csc.exe.

2. List and explain the basic output options available with C# complier.

3. Illustrate with an example, how do you compile multiple source files?

4. What are response files? Explain with an example.

5. How do you generate bug reports? Illustrate with an example.

6. What are C# preprocessor directives? Explain.

7. Explain the use of System.Environment class with a program.

Module 1

R.V.COLLEGE OF ENGINEERING Page 65

Page 66: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Unit 4

CONTENTS:

1.18 Objectives4.2 Introduction

4.3The Anatomy of a Basic C# Class

4.4Creating Objects: Constructor Basics

4.5The Composition of a C# Application

4.6Default Assignment and Variable scope

4.7The C# Member Initialization Syntax

4.8Basic Input and Output with the Console Class

4.9Defining Program Constants

4.10 C# Iteration Constructs

4.11 C# Controls Flow Constructs

4.12 The Complete set of C# Operators

4.13 Summary

4.14 Keywords

4.15 Exercises

4.1 Objectives

At the end of this lesson, the students will understand:

The structure of C# class

Constructors

R.V.COLLEGE OF ENGINEERING Page 66

Page 67: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Composition of C# Application

Variables, Input/Output with Console Class

Constants

Iterative and Repetitive Constructs

Operators

4.2 Introduction

In this unit, we will discuss basic concepts about C# programming language. The

syntax of the C# program, key words, variable initialization, declaration of

constants etc. are discussed here. The reading of data from the keyboard, writing

the data onto the monitor have to be revealed. The basic programming conditional

constructs like if, if-else, switch statements, the looping constructs like for, while,

do/while etc are revealed. Then various operators like arithmetic, logical, relational

operators supported by C# are discussed.

4.3 The Anatomy of a Basic C# Class

In C#, all program logic must be contained within a type definition (type may be a

member of the set {class, interface, structure, enumeration, delegate}). Unlike C or

C++, in C# it is not possible to create global functions or global points of data. In its

simplest form, a C# program can be written as follows:

Program 4.1 Test.cs

using System;

class Test

{

R.V.COLLEGE OF ENGINEERING Page 67

Page 68: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

public static int Main(string[] args)

{

Console.WriteLine("Hello World!");

return 0;

}

}

Every executable C# application must contain a class defining a Main() method,

which is used to signify the entry point of the application. Main() is used with the

public and static keywords. The public members are accessible from other types,

while static members are scoped at the class level (rather than the object level) and

can thus be invoked without the need to first create a new class instance (or

object). In addition to the public and static keywords, this Main() method has a

single parameter, which is an array of strings (string[] args). This parameter may

contain any number of incoming command-line arguments.

The program Test.cs makes use of the Console class, which is defined within the

System namespace. WriteLine() is a static member of Console class, which is used

to pump a text string to the standard output.

NOTE: We can use Console.ReadLine() to ensure the command prompt launched by

Visual Studio 2005 remains visible during a debugging session until we press the

Enter key.

Variations on the Main() Method

The Main() function can be take any of the following forms based on our

requirement:

R.V.COLLEGE OF ENGINEERING Page 68

Page 69: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

// No return type, array of strings as argument.

public static void Main(string[] args)

{

//some code

}

// No return type, no arguments.

public static void Main()

{

//some code

}

// Integer return type, no arguments.

public static int Main()

{

//some code

//return a value to OS

}

NOTE: The Main() method may also be defined as private. Doing so ensures other

assemblies cannot directly invoke an application’s entry point. Visual Studio 2005

automatically defines a program’s Main() method as private. Obviously, your choice

of how to construct Main() will be based on two questions. First, do you need to

process any user-supplied command-line parameters? If so, they will be stored in

the array of strings. Second, do you want to return a value to the system when

Main() has completed? If so, you need to return an integer data type rather than

void.

R.V.COLLEGE OF ENGINEERING Page 69

Page 70: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Processing Command-Line Arguments

Assume that we need some arguments to be passed as input to the Main() funtion

before starting the program execution. This is done through command-line

parameters. Consider an example –

Program 4.2

using System;

class Test

{

public static int Main(string[] args)

{

Console.WriteLine("***** Command line args *****");

for(int i = 0; i < args.Length; i++)

Console.WriteLine("Arg: {0} ", args[i]);

}

}

Here, we are checking to whether the array of strings contains some number of

items using the Length property of System.Array. We can provide command line

arguments while running the program as –

Test.exe Good Bad Ugly

As an alternative to the standard for loop, we may iterate over incoming string

arrays using the C# foreach keyword. For example –

R.V.COLLEGE OF ENGINEERING Page 70

Page 71: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

// Notice you have no need to check the size of the array //when using 'foreach'.

public static int Main(string[] args)

{

...

foreach(string s in args)

Console.WriteLine("Arg: {0} ", s);

...

}

It is also possible to access command-line arguments using the static GetCommand-

LineArgs() method of the System.Environment type. The return value of this method

is an array of strings. The first index identifies the current directory containing the

application itself, while the remaining elements in the array contain the individual

command-line arguments. If we are using this technique, we need not define the

Main() method with string array parameter. Consider an example –

public static int Main() //no arguments

{

// Get arguments using System.Environment.

string[] Args = Environment.GetCommandLineArgs();

Console.WriteLine("Path to this app is: {0}", Args[0]);

for(int i=1; i<Args.Length;i++)

Console.WriteLine("Arguments are: {0}", Args[i]);

}

R.V.COLLEGE OF ENGINEERING Page 71

Page 72: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

4.4 Creating Objects: Constructor Basics

All object-oriented (OO) languages make a clear distinction between classes and

objects. A class is a definition (or, if you will, a blueprint) for a user-defined type

(UDT). An object is simply a term describing a given instance of a particular class in

memory. In C#, the new keyword is used to create an object. Unlike other OO

languages (such as C++), it is not possible to allocate a class type on the stack;

therefore, if you attempt to use a class variable that has not been “new-ed,” you

are issued a compile-time error. Thus the following C# code is illegal:

using System;

class Test

{

public static int Main(string[] args)

{

Test c1;

c1.SomeMethod(); //error!! Must use “new”

...

}

}

To illustrate the proper procedures for object creation, consider the following code:

using System;

R.V.COLLEGE OF ENGINEERING Page 72

Page 73: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

class Test

{

public static int Main(string[] args)

{

// You can declare and create a new object in a single line...

Test c1 = new Test();

// ...or break declaration and creation into two lines.

Test c2;

c2 = new Test();

...

}

}

The new keyword will calculate the correct number of bytes for the specified object

and acquires sufficient memory from the managed heap. Here, we have allocated

two objects c1 and c2, each of which points to a unique instance of Test type. Note

that C# object variables are really a reference to the object in memory, not the

actual object itself. Thus, c1 and c2 each reference a distinct Test object allocated

on the managed heap.

In the previous program, the objects have been constructed using the default

constructor, which by definition never takes arguments. Every C# class is

automatically provided with a free default constructor, which you may redefine if

needed. The default constructor ensures that all member data is set to an

appropriate default value. But in C++, un-initialized data gets garbage value.

R.V.COLLEGE OF ENGINEERING Page 73

Page 74: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Usually, classes provide additional constructors also. Using this, we can initialize the

object variables at the time of object creation. Like in Java and C++, in C#

constructors are named identically to the class they are constructing, and they

never provide a return value (not even void).

Consider the following example –

Program 4.3

using System;

class Test

{

public string userMessage;

// Default constructor.

public Test()

{

Console.WriteLine("Default constructor called!");

}

public Test (string msg)

{

Console.WriteLine("Custom ctor called!");

userMessage = msg;

}

public static int Main(string[] args)

R.V.COLLEGE OF ENGINEERING Page 74

Page 75: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

{

// Call default constructor.

Test c1 = new Test ();

Console.WriteLine("Value of userMessage: {0}\n", c1.userMessage);

// Call parameterized constructor.

Test c2;

c2 = new Test ("Hello World");

Console.WriteLine("Value of userMessage: {0}", c2.userMessage);

Console.ReadLine();

return 0;

}

}

NOTE:

1. Technically speaking, when a type defines identically named members

(including constructors) that differ only in the number of—or type of—

parameters, the member in question is overloaded.

2. As soon as we define a custom constructor for a class type, the free default

constructor is removed. If we want to create an object using the default

constructor, we need to explicitly redefine it as in the preceding example.

Is That a Memory Leak?

Note that, in previous program, we have not written any code to explicitly destroy

the c1 and c2 references. In C++, if we do like this, it will lead to memory leak. But,

the .NET garbage collector frees the allocated memory automatically, and therefore

C# does not support a delete keyword.

R.V.COLLEGE OF ENGINEERING Page 75

Page 76: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

4.5 The Composition of a C# Application

We have seen in the previous example that the Main() function creates instances of

the very own class in which it is defined. However, a more natural way to write an

application using distinct classes is as shown in the following example. In OO

terminology, this way of writing an application is known as Separation of

concerns.

Program 4.4 MyTest.cs

using System;

class Test

{

public Test()

{

Console.WriteLine("Default constructor called!");

}

public void disp()

{

Console.WriteLine("Hi");

}

}

class MyTest

{

public static void Main(string[] args)

R.V.COLLEGE OF ENGINEERING Page 76

Page 77: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

{

Test c1 = new Test ();

c1.disp();

}

}

The type (like class, structure etc) containing Main() function (that is, entry point for

the application) is called as the application object. Every C# application will be

having one application object and numerous other types. On the other hand, we can

create an application object that defines any number of members called from the

Main() method.

4.6 Default Assignments and Variable Scope

All intrinsic .NET data types have a default value. When we create custom types, all

member variables are automatically assigned to their respective default values.

Consider an example –

Program 4.5

using System;

class Test

{

public int a; //default value is 0

public byte b; //default value is 0

public char c; //default value is null

public string s; //default value is null

R.V.COLLEGE OF ENGINEERING Page 77

Page 78: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

public static void Main()

{

Test t=new Test();

Console.WriteLine(“{0}, {1}, {2}, {3}”, a, b, c, s);

}

}

All the variables will be initialized to their default values when we start debugging.

However, we can not expect the same within method scope. For example, the

following program will generate an error.

using System;

class Test

{

public static void Main()

{

int a; //need to assign some value to ‘a’

Console.WriteLine(“{0}”, a); //Error:Unassigned local variable ‘a’

}

}

NOTE: There is an exception for the mandatory assignment of a local variable. If

the local variable is used as an output parameter, then it need not be initialized

before use. Output parameters are discussed later in detail. However, note that,

they are used to receive the value from a function.

R.V.COLLEGE OF ENGINEERING Page 78

Page 79: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

4.7 The C# Member Variable Initialization Syntax

Consider a class (or any other type) having more than one constructor with different

set (may be different in type or number) of arguments. Now, if any member variable

needs to be initialized with same value in all the situations, we need to write the

code repeatedly in all the constructors. For example,

class Test

{

private int a;

Test()

{

a=5;

}

Test(int k)

{

a=5;

…….

}

Test(string s)

{

a=5;

…….

}

R.V.COLLEGE OF ENGINEERING Page 79

Page 80: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

}

Though the above code is valid, there is redundancy in code. We can write a

function for such initialization like –

class Test

{

private int a;

public void init()

{

a=5;

}

Test()

{

init();

}

Test(int k)

{

init()

…….

}

Test(string s)

R.V.COLLEGE OF ENGINEERING Page 80

Page 81: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

{

init()

…….

}

}

Here we have function call instead of assignment. Thus, redundancy still exists. To

avoid such situation, C# provides the initialization of member variables directly

within a class as shown –

class Test

{

private int a =5;

private string s= “Hello”;

…………..

}

This facility was not available in C++. Note that, such an initialization will happen

before the constructor gets called. Hence, if we provide any other value to a

variable through constructor, the previous member assignment will be overwritten.

4.8 Basic Input and Output with the Console Class

R.V.COLLEGE OF ENGINEERING Page 81

Page 82: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

In many of the programs what we have seen till now, made use of System.Console

class. As the name suggests, Console class is defined in System namespace and it

encapsulates input, output and error stream manipulations. This class is widely

used for console applications but not for Windows or Web applications.

There are four important static methods in Console class:

Read() Used to capture a single character from the input stream.

ReadLine() Used to receive information from the input stream until the

enter key is pressed.

Write() This method pumps text to the output stream without

carriage return (enter key)

WriteLine() This pumps a text string including carriage return to the

output stream.

Following table gives some important member of Console class:

Member MeaningBackgroundColorForegroundColor

These properties set the background/foreground colors for the current output. They may be assigned any member of the ConsoleColor enumeration.

BufferHeightBufferWidth

These properties control the height/width of the console’s buffer area.

Clear() This method clears the buffer and console display area.Title This property sets the title of the current console.WindowHeight WindowWidth WindowTopWindowLeft

These properties control the dimensions of the console in relation to the established buffer.

To illustrate the working of Console class methods, consider the following example –

Program 4.6

using System;

R.V.COLLEGE OF ENGINEERING Page 82

Page 83: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

class BasicIO

{

public static void Main()

{

Console.Write("Enter your name: ");

string s = Console.ReadLine();

Console.WriteLine("Hello, {0} ", s);

Console.Write("Enter your age: ");

s = Console.ReadLine();

Console.WriteLine("You are {0} years old", s);

}

}

The output would be –

Enter your name: Ramu

Hello, Ramu

Enter your age: 25

You are 25 years old

Formatting Textual Output

In the previous examples, we have seen numerous occurrences of the tokens {0},

{1} etc. embedded within a string literal. .NET introduces a new style of string

formatting. A simple example follows –

static void Main(string[] args)

{

R.V.COLLEGE OF ENGINEERING Page 83

Page 84: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

...

int i = 90;

double d = 9.99;

bool b = true;

Console.WriteLine("Int is: {0}\nDouble is: {1}\nBool is: {2}", i, d, b);

}

The first parameter to WriteLine() represents a string literal that contains optional

placeholders designated by {0}, {1}, {2}, and so forth (curly bracket numbering

always begins with zero). The remaining parameters to WriteLine() are simply the

values to be inserted into the respective placeholders.

Note that WriteLine() has been overloaded to allow the programmer to specify

placeholder values as an array of objects. Thus, we can represent any number of

items to be plugged into the format string as follows:

// Fill placeholders using an array of objects.

object[] stuff = {"Hello", 20.9, 1, "There", "83", 99.99933} ;

Console.WriteLine("The Stuff: {0} , {1} , {2} , {3} , {4} , {5} ", stuff);

It is also permissible for a given placeholder to repeat within a given string. For

example, if we want to build the string "9, Number 9, Number 9" we can write

Console.WriteLine("{0}, Number {0}, Number {0}", 9);

R.V.COLLEGE OF ENGINEERING Page 84

Page 85: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Note If any mismatch occurs between the number of uniquely numbered curly-

bracket placeholders and fill arguments, an exception viz. FormatException is

popped up at runtime.

.NET String Formatting Flags

If we require more detailed formatting, each placeholder can optionally contain

various format characters (in either uppercase or lowercase), as shown –

C# Format Character

Meaning

C or c Used to format currency. By default, the flag will prefix the local cultural symbol (a dollar sign [$] for U.S. English). However, this can be changed using a System.Globalization.NumberFormatInfo object

D or d Used to format decimal numbers. This flag may also specify the minimum number of digits used to pad the value.

E or e Used for exponential notation.F or f Used for fixed-point formatting.G or g Stands for general. This character can be used to format a number to

fixed or exponential format.N or n Used for basic numerical formatting (with commas).X or x Used for hexadecimal formatting. If you use an uppercase X, your hex

format will also contain uppercase characters.

These format characters are suffixed to a given placeholder value using the colon

token (e.g., {0:C}, {1:d}, {2:X}, and so on). Consider an example:

Program 4.7

using System;

class Test

{

public static void Main(string[] args)

{

R.V.COLLEGE OF ENGINEERING Page 85

Page 86: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Console.WriteLine("C format: {0:C}", 99989.987);

Console.WriteLine("D9 format: {0:D9}", 99999);

Console.WriteLine("E format: {0:E}", 99999.76543);

Console.WriteLine("F3 format: {0:F3}", 99999.9999);

Console.WriteLine("N format: {0:N}", 99999);

Console.WriteLine("X format: {0:X}", 99999);

Console.WriteLine("x format: {0:x}", 99999);

}

}

The output would be –

C format: $99,989.99

D9 format: 000099999

E format: 9.999977E+004

F3 format: 100000.000

N format: 99,999.00

X format: 1869F

x format: 1869f

Note that the use of .NET formatting characters is not limited to console

applications. These same flags can be used within the context of the static

String.Format() method. This can be helpful when we need to create a string

containing numerical values in memory for use in any application type (Windows

Forms, ASP.NET, XML web services, and so on):

Program 4.8

R.V.COLLEGE OF ENGINEERING Page 86

Page 87: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

using System;

class Test

{

static void Main(string[] args)

{

string Str;

Str = String.Format("You have {0:C} in your account", 99989.987);

Console.WriteLine(Str);

}

}

The output would be –

You have $99,989.99 in your account

4.9 Defining Program Constants

C# provides a const keyword to defined variables with a fixed, unalterable value.

The value of a constant data is computed at compile time and hence, a constant

variable can not be assigned to an object reference (whose value is computed at

runtime). That is, boxing (will discuss this in next module) is not possible for

constant variables. We can define either class-level constants or local-level (within a

method) constants. For example,

Program 4.9

using System;

R.V.COLLEGE OF ENGINEERING Page 87

Page 88: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

abstract class ConstClass

{

public const int p=10;

public const string s="I am a constant";

}

class Test

{

public const int x=5;

public static void Main()

{

const int y=20;

Console.WriteLine("{0},{1},{2},{3}", ConstClass.p, ConstClass.s, x, y);

}

}

The output would be –

10, I am a constant, 5, 20

4.10 C# Iteration Constructs

R.V.COLLEGE OF ENGINEERING Page 88

Page 89: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Similar to any other programming language, C# provides following iteration

constructs:

for Loop

foreach/in Loop

while Loop

do/while Loop

The for Loop

The for loop in C# is just similar to that in C, C++ or Java. This loop will allow to

repeat a set of statements for fixed number of times. For example –

for(int i=0; i<10;i++)

Console.WriteLine(“{0}”, i); //0 to 9 will be printed.

We can use any type of complex terminating conditions, incrementation/

decrementation, continue, break, goto etc. while using for loop.

The foreach/in Loop

This loop is used to iterate over all items within an array. The following example

shows how each element of an integer array is considered within a loop.

Program 4.10

R.V.COLLEGE OF ENGINEERING Page 89

Page 90: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

using System;

class Test

{

public static void Main()

{

int[] arr=new int[]{5, 32, 10, 45, 63};

foreach(int i in arr)

Console.WriteLine("{0}",i);

}

}

Apart from iterating over simple arrays, foreach loop is used to iterate over system

supplied or user-defined collections. This will be discussed in later chapters.

The while and do/while Loop

When we don’t know the exact number of times a set of statements to be executed,

we will go for while loop. That is, a set of statements will be executed till a

condition remains true. For example,

string s;

while((s=Console.ReadLine())!=null)

Console.WriteLine(“{0}”, s);

Some times, we need a set of statements to be executed at least once, irrespective

of the condition. Then we can go for do/while loop. For example,

R.V.COLLEGE OF ENGINEERING Page 90

Page 91: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

string opt;

do

{

Console.Write(“Do you want to continue?(Yes/No):”);

opt=Console.ReadLine();

}while(opt!=”Yes”);

4.11 C# Control Flow Constructs

There are two control flow constructs in C# viz. if/else and switch/case. The if/else

works only on boolean expressions. So we can not use the values 0, 1 etc. within if

as we do in C/C++. Thus, the if statement in C# typically involve the relational

operators and/or conditional operators.

The following two tables lists out the relational and logical operators respectively.

Relational Operator Meaning== To check equality of two operands!= Not equal to< Less than> Greater than

<= Less than or equal to>= Greater than or equal to

Conditional/Logical Operator Meaning&& Logical AND|| Logical OR! Logical NOT

R.V.COLLEGE OF ENGINEERING Page 91

Page 92: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

The general form of if can be given as –

if(condition)

{

//true block

}

else

{

//false block

}

The general from of switch can be given as –

switch(variable/expression)

{

case val1: //statements;

break;

case val2: //statements;

break;

--------------

--------------

case val2: //statements;

break;

}

R.V.COLLEGE OF ENGINEERING Page 92

Page 93: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

4.12 Complete set of C# Operators

Following is a set of operators provided by C#.

Operator Category OperatorsUnary +, -, !, ~, ++, --Multiplicative *, /, %Additive +, -Shift <<, >>Relational <, >, <=. >=, is, asEquality ==, !=Logical & (AND), ^ (XOR), | (OR)Conditional &&, ||, ?: (ternary operator)Indirection/Address *, ->, &Assignment =, *=, -=, +=, /=, %=, <<=, >>=, &=, ^=,

|=

The relational operator is is used to verify at runtime whether an object is

compatible with a given type or not. The as operator is used to downcast between

types. We will discuss this later in detail. As C# supports inter-language interaction,

it supports the C++ pointer manipulation operators like *, -> and &. But if we use

any of these operators, we are going bypass the runtime memory management

scheme and writing code in unsafe mode.

4.13 Summary

This unit has exposed you to the numerous core aspects of the C# programming

Language. The focus was to examine the constructs that will be commonplace in

any application you may be interested in building. First, every C# program must

have a class defining a static Main() method, which serves as the entry point of the

program. Within the scope of Main(), you typically create any number of objects

which work together to breathe life into your application. Then you have explored

R.V.COLLEGE OF ENGINEERING Page 93

Page 94: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

basic requirements like I/O operations, variable declaration and scope, control flow

etc. of the programming language.

4.14 Keywords Command Line arguments The keyword new Reference to an object Constructor: Default and Parameterized Separation of concerns Application object System.Console class Formatting outputs The Keyword const The loops for, foreach/in, while, do/while The conditional constructs if/else, switch/case The Operators is, as

4.15 Exercises

1. Explain variations in Main() function.

2. What are basic input and output functions with Console class? Explain.

3. Write a C# program to illustrate command line arguments.

4. Write a note on formatting textual input.

5. List out string formatting flags? Explain with example.

6. Write a C# program to illustrate foreach/in Loop.

7. Write a C# application which defines a class Shape, with four data members

length, breadth, height and radius, appropriate constructors and methods to

calculate volume of cube, cone and sphere. Also write a class ShapeApp, which

creates these 3 objects i.e. cube, cone and sphere using appropriate

constructors and calculates their volume with the help of above class methods.

R.V.COLLEGE OF ENGINEERING Page 94

Page 95: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Module 2

Unit 1

CONTENTS:

1.19 Objectives1.20 Introduction1.21 Understanding Value Types and Reference Types1.22 The Master Node: System.Object1.23 The System Data Types (and C# Aliases)1.24 Converting between value types reference types: Boxing

and Unboxing

1.25 Summary1.26 Keywords1.27 Exercises

1.16 Objectives

At the end of this lesson, the students will understand:

Two types in .NET viz. value types and reference types

The topmost base class System.Object

Various methods of System.Object class, overriding these methods

Various data types available in C#

Boxing and Unboxing

1.17 Introduction

We have seen from the first module that .NET provides common language runtime

for all the programming languages supported on its platform. As a part of CLR, any

R.V.COLLEGE OF ENGINEERING Page 95

Page 96: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

type in .NET or more specifically C#, can be either of value type or of reference

type. These two types have their own way of usage and properties. Moreover, in

C#, everything that we use in a program is derived from a topmost base class

called System.Object. In this unit, we are going discuss all these factors in detail.

1.18 Understanding Value Types and Reference Types

Like any programming language, C# defines a number of keywords that represent

basic data types such as whole numbers, character data, floating-point numbers,

and Boolean values. These intrinsic types are fixed constants. That is, all .NET-

aware languages understand the fixed nature of these intrinsic types, and all agree

on the range it is capable of handling.

A .NET data type may be value-based or reference-based. Value-based types,

which include all numerical data types (int, float, etc.) as well as enumerations and

structures, are allocated on the stack. So, value types can be quickly removed from

memory once they are out of the defining scope:

public void SomeMethod()

{

int i = 0;

Console.WriteLine(i);

} // 'i' is removed from the stack here

R.V.COLLEGE OF ENGINEERING Page 96

Page 97: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

When we assign one value type to another, a member-by-member (or a bit-wise)

copy is achieved by default. In terms of numerical or Boolean data types, the only

“member” to copy is the value of the variable itself:

public void SomeMethod()

{

int i = 99;

int j = i;

j = 8732; // j will be 8732 and i remains to be 99

}

This example may not seem special. But, now we will have a look at other value

types like structures and enumerations. Structures provide a way to achieve the

benefits of object orientation (i.e., encapsulation) while having the efficiency of

stack-allocated data. Like a class, structures can take constructors (only

parameterized constructors) and define any number of members. All structures are

implicitly derived from a class named System.ValueType. The purpose of

System.ValueType is to “override” the virtual methods defined by System.Object to

support value-based v/s reference-based semantics. In fact, the instance methods

defined by System.ValueType are identical to those of System.Object.

Consider an example to illustrate the working of value types –

Program 1.1 File Name: MyClass.cs

struct MyStruct

{

R.V.COLLEGE OF ENGINEERING Page 97

Page 98: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

public int x;

}

class MyClass

{

public static void Main()

{

// the keyword new is optional while creating structures.

MyStruct ms1 =new MyStruct();

ms1.x = 100;

MyStruct ms2 = ms1;

Console.WriteLine("ms1.x = {0}", ms1.x); //100

Console.WriteLine("ms2.x = {0}", ms2.x); //100

ms2.x = 900;

Console.WriteLine("ms1.x = {0}", ms1.x); //100

Console.WriteLine("ms2.x = {0}", ms2.x); //900

}

}

The Output will be –

ms1.x = 100

ms2.x = 100

R.V.COLLEGE OF ENGINEERING Page 98

Page 99: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

ms1.x = 100

ms2.x = 900

Note that, to allocate a structure type, we can use the ‘new’ keyword. This will

create an impression that memory is allocated in heap. But, this is not true. CLR

makes the programmer to feel everything is an object and new value types.

However, when the runtime encounters a type derived from System.ValueType,

stack allocation is achieved.

In the above program, we have created a variable ms1 and then it is assigned to

ms2. Since MyStruct is a value type, we will have two copies of the MyStruct type

on the stack, each of which can be independently manipulated. Therefore, when we

change the value of ms2.x, the value of ms1.x is unaffected.

On the other hand, the reference types (classes) are allocated on the managed

heap. These objects stay in memory until the .NET garbage collector destroys them.

By default, assignment of reference types results in a new reference to the same

object on the heap. To illustrate, let us change the above example:

Program 1.2 File Name: MyClass1.cs

class MyClass //struct has been changed to class

{

public int x;

}

class MyClass1

R.V.COLLEGE OF ENGINEERING Page 99

Page 100: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

{

public static void Main()

{

MyClass mc1 =new MyClass (); // new is compulsory

mc1.x = 100;

MyClass mc2 = mc1;

Console.WriteLine("mc1.x = {0}", mc1.x); //100

Console.WriteLine("mc2.x = {0}", mc2.x); //100

ms2.x = 900;

Console.WriteLine("mc1.x = {0}", mc1.x); //900

Console.WriteLine("mc2.x = {0}", mc2.x); //900

}

}

The Output will be –

mc1.x = 100

mc2.x = 100

mc1.x = 900

mc2.x = 900

R.V.COLLEGE OF ENGINEERING Page 100

Page 101: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

In this example, we have two references pointing to the same object on the

managed heap. Therefore, when we change the value of x using the mc2 reference,

mc1.x reports the same value.

Value Types Containing Reference Types

Assume that we have a reference (class) type MyClass containing a constructor to

assign value to a member variable of type string. Assume also that we have

included object of this class within a structure MyStruct. We have included the

Main() function in another class and the total application is as given below –

Program 1.3 Name of file: Test.cs

using System;

class MyClass

{

public string s;

public MyClass(string str) //constructor for class

{

s=str;

}

}

struct MyStruct

{

public MyClass mc;

public int a;

R.V.COLLEGE OF ENGINEERING Page 101

Page 102: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

public MyStruct(string str) //constructor for structure

{

mc=new MyClass(str); //calling constructor of class

a=10;

}

}

class Test

{

public static void Main(string[] args)

{

MyStruct ms1=new MyStruct("Initial Value");

ms1.a=15;

MyStruct ms2=ms1;

ms2.mc.s="New Value!!!";

ms2.a=20;

Console.WriteLine("ms1.mc.s is {0}", ms1.mc.s);

Console.WriteLine("ms2.mc.s is {0}", ms2.mc.s);

Console.WriteLine("ms1.a is {0}", ms1.a);

Console.WriteLine("ms2.a is {0}", ms2.a);

}

}

R.V.COLLEGE OF ENGINEERING Page 102

Page 103: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

The Output would be –

ms1.mc.s is New Value!!!

ms2.mc.s is New Value!!!

ms1.a is 15

ms2.a is 20

Now compare the programs 1.1, 1.2 and 1.3.

In Program 1.1, we have used the structure, which is of value type. So,

when we use the statement

MyStruct ms2= ms1;

there will be separate memory allocation for two objects (Memory will be

allocated from stack). Thus, the assignment statement ms2=ms1 will copy

the contents of ms1 to the corresponding variables of ms2. Since memory

allocation is different for these two objects, the change in one object doesn’t

affect the other object.

In Program 1.2, we have used the class, which is of reference type. So,

when we use the statement

MyClass mc2 = mc1,

mc2 will be just reference to mc1 sharing the same memory location in the

heap. Also, the contents of mc1 will be copied to the corresponding variables

of mc2. Since memory location is same for both the objects, the change in

one object will affect the other object.

In Program 1.3, we have a value type MyStruct containing an object of

reference type MyClass. The object ms1 of MyStruct contains an object mc of

R.V.COLLEGE OF ENGINEERING Page 103

Page 104: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

MyClass and an integer variable a. Here, a will be allocated memory from

stack and mc will get memory from heap. Now, when we use the statement

MyStruct ms2=ms1;

the object ms2 gets created. Note that, ms1.a and ms2.a will have different

memory allocation as a is member of structure. But, ms1.mc.s and ms2.mc.s

will point to same location in heap memory as s is basically a member of

class. This can be diagrammatically represented as–

Thus, when a value type contains other reference types, assignment results in a

copy of the references. In this way, we have two independent structures ms1 and

ms2 each of which contains a reference pointing to the same object in memory (i.e.,

a “shallow copy”). When we want to perform a “deep copy,” where the state of

internal references is fully copied into a new object, we need to implement the

ICloneable interface, which we will see later in detail.

Value and Reference Types: Final Details

Following table summarizes the core distinctions between value types and

reference types.

R.V.COLLEGE OF ENGINEERING Page 104

ms1 ms2

a s a

Page 105: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Intriguing Question Value Type Reference Type

Where is this type allocated?

Allocated on the stack Allocated on the managed heap.

How is a variable represented?

Value type variables are local copies.

Reference type variables are pointing to the memory occupied by the allocated instance.

What is the base type? Must derive from System.ValueType.

Can derive from any other type (except System.ValueType), as long as that type is not “sealed”

Can this type function as a base to other types?

No. Value types are always sealed and cannot be extended.

Yes. If the type is not sealed, it may function as a base to other types.

What is the default parameter passing behavior?

Variables are passed by value (i.e., a copy of the variable is passed into the called function).

Variables are passed by reference (e.g., the address of the variable is passed into the called function).

Can this type override System.Object.Finalize()?

No. Value types are never placed onto the heap and therefore do not need to be finalized.

Yes, indirectly

Can we define constructors?

Yes, but the default constructor is reserved

Yes

When do variables of this type die?

When they fall out of the defining scope.

When the managed heap is garbage collected.

Despite their differences, value types and reference types both have the ability to

implement interfaces and may support any number of fields, methods, overloaded

operators, constants, properties, and events.

1.19 The Master Node: System.Object

In .NET, every data type is derived from a common base class: System.Object. The

Object class defines a common set of members supported by every type in the .NET

R.V.COLLEGE OF ENGINEERING Page 105

Page 106: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

framework. When we create a class, it is implicitly derived from System.Object. For

example, the following declaration is common way to use.

class Test

{

...

}

But, internally, it means that,

class Test : System.Object

{

...

}

System.Object defines a set of instance-level (available only after creating objects)

and class-level (static) members. Note that some of the instance-level members are

declared using the virtual keyword and can therefore be overridden by a derived

class:

// The structure of System.Object class

namespace System

{

public class Object

{

public Object();

public virtual Boolean Equals(Object obj);

R.V.COLLEGE OF ENGINEERING Page 106

Page 107: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

public virtual Int32 GetHashCode();

public Type GetType();

public virtual String ToString();

protected virtual void Finalize();

protected Object MemberwiseClone();

public static bool Equals(object objA, object objB);

public static bool ReferenceEquals(object objA, object objB);

}

}

Following table shows some of the functionality provided by each instance-level method.

Instance Method of Object Class

Meaning

Equals() By default, this method returns true only if the items being compared refer to the exact same item in memory. Thus, Equals() is used to compare object references, not the state of the object. Typically, this method is overridden to return true only if the objects being compared have the same internal state values. Note that if you override Equals(), you should also override GetHashCode().

GetHashCode() This method returns an integer that identifies a specific object in memory. If you intend your custom types to be contained in a System.Collections.Hashtable type, you are well-advised to override the default implementation of this member.

GetType() This method returns a System.Type object that fully describes the details of the current item. In short, this is a Runtime Type Identification (RTTI) method available to all objects.

ToString() This method returns a string representation of a given object, using the namespace.typename format (i.e., fully qualified name). If the type has not been defined within a namespace, typename alone is returned. This method can be overridden by a subclass to return a tokenized string of name/value pairs that represent the object’s internal state, rather than its fully qualified name.

Finalize() This protected method (when overridden) is invoked by the .NET runtime when an object is to be removed from the heap (during garbage collection).

R.V.COLLEGE OF ENGINEERING Page 107

Page 108: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

MemberwiseClone() This protected method exists to return a new object that is a member-by-member copy of the current object. Thus, if the object contains references to other objects, the references to these types are copied (i.e., it achieves a shallow copy). If the object contains value types, full copies of the values are achieved. (Example, Program 1.3)

The Default Behavior of System.Object

To illustrate some of the default behavior provided by the System.Object base class,

consider the following example –

Program 1.4

using System;

class Person

{

public string Name, SSN;

public byte age;

public Person(string n, string s, byte a)

{

Name = n;

SSN = s;

age = a;

}

public Person(){ }

static void Main(string[] args)

{

Console.WriteLine("***** Working with Object *****\n");

R.V.COLLEGE OF ENGINEERING Page 108

Page 109: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Person p1 = new Person("Ram", "111-11-1111", 20);

Console.WriteLine("p1.ToString: {0}", p1.ToString());

Console.WriteLine("p1.GetHashCode: {0}", p1.GetHashCode());

Console.WriteLine("p1’s base class: {0}", p1.GetType().BaseType);

Person p2 = p1;

object o = p2;

if(o.Equals(p1) && p2.Equals(o))

Console.WriteLine("p1, p2 and o are same objects!");

}

}

The Output would be –

***** Working with Object *****

p1.ToString: Person

p1.GetHashCode: 58225482

p1's base class: System.Object

p1, p2 and o are same objects!

We can notice from the above program that the default implementation of

ToString() simply returns the fully qualified name of the type. GetType() retrieves a

System.Type object, which defines a property named . Here, new Person object p1

is referencing memory in the heap. p2 is also of type Person, however, we are not

creating a new instance of the Person class, but assigning p2 to p1. Therefore, p1

and p2 are both pointing to the same object in memory. Similarly the variable o (of

R.V.COLLEGE OF ENGINEERING Page 109

Page 110: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

type object) also refers to the same memory. Thus, when we compare p1, p2 and o,

it says that all are same.

Overriding Some Default Behaviors of System.Object

In many of our applications, we may want to override some of the behaviors of

System.Object. Overriding is the process of redefining the behavior of an inherited

virtual member in a derived class. We have seen that System.Object class has some

virtual methods like ToString(), Equals() etc. These can be overridden by the

programmer.

Overriding ToString()

Consider the following example to override System.Object.ToString().

Program 1.5

using System;

using System.Text;

class Person

{

public string Name, SSN;

public byte age;

public Person(string n, string s, byte a)

{

R.V.COLLEGE OF ENGINEERING Page 110

Page 111: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Name = n;

SSN = s;

age = a;

}

public Person(){ }

// Overriding System.Object.ToString()

public override string ToString()

{

StringBuilder sb = new StringBuilder();

sb.AppendFormat("[Name={0}", this. Name);

sb.AppendFormat(" SSN={0}", this.SSN);

sb.AppendFormat(" Age={0}]", this.age);

return sb.ToString();

}

public static void Main()

{

Person p1 = new Person(“Ram”, “11-12”, 25);

Console.WriteLine(“p1 is {0}”, p1.ToString());

}

}

The Output would be –

p1 is [Name=Ram SSN=11-12 Age=25]

R.V.COLLEGE OF ENGINEERING Page 111

Page 112: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

In the above example, we have overridden ToString() method to display the

contents of the object in the form of tuple. The System.Text.StringBuilder is class

which allows access to the buffer of character data and it is a more efficient

alternative to C# string concatenation (Discussed later in detail).

Overriding Equals()

By default, System.Object.Equals() returns true only if the two references being

compared are referencing same object in memory. But in many situations, we are

more interested if the two objects have the same content. Consider an example –

Program 1.6

using System;

class Person

{

public string Name, SSN;

public byte age;

public Person(string n, string s, byte a)

{

Name = n;

SSN = s;

age = a;

}

R.V.COLLEGE OF ENGINEERING Page 112

Page 113: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

public Person(){ }

public override bool Equals(object ob)

{

if (ob != null && ob is Person)

{

Person p = (Person)ob;

if (p.Name == this.Name && p.SSN == this.SSN && p.age == this.age)

return true;

}

return false;

}

public static void Main()

{

Person p1 = new Person("Ram", "11-12", 25);

Person p2 = new Person("Shyam", "11-10", 20);

Person p3 = new Person("Ram", "11-12", 25);

Person p4 = p2;

if(p1.Equals(p2))

Console.WriteLine("p1 and p2 are same");

else

Console.WriteLine("p1 and p2 are not same");

R.V.COLLEGE OF ENGINEERING Page 113

Page 114: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

if(p1.Equals(p3))

Console.WriteLine("p1 and p3 are same");

else

Console.WriteLine("p1 and p3 are not same");

if(p2.Equals(p4))//compares based on content, not on reference

Console.WriteLine("p4 and p2 are same");

else

Console.WriteLine("p4 and p2 are not same");

}

}

The Output would be –

p1 and p2 are not same

p1 and p3 are same

p4 and p2 are same

While overriding the Equals() method, first we are checking whether the passed

object is of class Person or not. Also, we need to check whether the object has been

allocated memory or it is having null. Note that Equals() method takes the

parameter of type object. Thus, we need to type-cast it to Person type before using

it. When we override Equals(), we need to override GetHashCode() too.

Overriding System.Object.GetHashCode()

R.V.COLLEGE OF ENGINEERING Page 114

Page 115: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

The GetHashCode() method is suitable for use in hashing algorithms

and data structures such as a hash table.

The GetHashCode() method returns a numerical value used to identify

an object in the memory.

The default implementation of the GetHashCode() method does not

guarantee unique return values for different objects.

Furthermore, the .NET Framework does not guarantee the default

implementation of the GetHashCode() method, and the value it returns

will be the same between different versions of the .NET Framework.

So, the default implementation of this method must not be used as a

unique object identifier for hashing purposes.

If we place a custom (user-defined) object into a

System.Collections.Hashtable type, its Equals() and GetHashCode()

members will determine the correct type to return from the container.

So, user-defined types should redefine the hashing algorithm used to

identify itself within such a type.

There are many algorithms that can be used to create a hash code. In the

simplest case, an object’s hash value will be generated by taking its data

into consideration and building a unique numerical identifier for the type. For

example, SSN will be unique for each individual. So, we can override

GetHashCode() method as below –

Program 1.7

using System;

class Person

{

public string Name, SSN;

R.V.COLLEGE OF ENGINEERING Page 115

Page 116: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

public byte age;

public Person(string n, string s, byte a)

{

Name = n;

SSN = s;

age = a;

}

public Person(){ }

public override int GetHashCode()

{

return SSN.GetHashCode();

}

public static void Main()

{

Person p1 = new Person("Ram", "11-12", 25);

Person p2 = new Person("Shyam", "11-10", 20);

Person p3 = new Person("Ram", "11-12", 25);

Person p4 = p2;

if(p1.Equals(p3)) //comparison based on reference

Console.WriteLine("p1 and p3 are same");

else

R.V.COLLEGE OF ENGINEERING Page 116

Page 117: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Console.WriteLine("p1 and p3 are not same");

if(p1.GetHashCode()==p3.GetHashCode()) //comparison based on SSN

Console.WriteLine("p1 and p3 are same");

else

Console.WriteLine("p1 and p3 are not same");

}

}

The output would be –

p1 and p3 are not same

p1 and p3 are same

1.20 The System Data Types (and C# Aliases)

Every intrinsic C# data type is an alias to an existing type defined in the System

namespace. Specifically, each C# data type aliases a well-defined structure type in

the System namespace. Following table lists each system data type, its range, the

corresponding C# alias and the type’s compliance with the CLS.

C# Alias

CLSCompliant?

System Type Range Meaning

sbyte No System.SByte -128 to 127 Signed 8-bit numberbyte Yes System.Byte 0 to 255 Unsigned 8-bit numbershort Yes System.Int16 -216 to 216-1 Signed 16-bit numberushort No System.UInt16 0 to 232-1 Unsigned 16-bit numberint Yes System.Int32 -232 to 232-1 Signed 32-bit numberuint No System.UInt32 0 to 264-1 Unsigned 32-bit numberlong Yes System.Int64 -264 to 264-1 Signed 64-bit numberulong No System.UInt64 0 to 2128-1 Unsigned 64-bit numberchar Yes System.Char U10000 to

U1ffffA Single 16-bit Unicode character

float Yes System.Single 1.5 x 10-45 to 32-bit floating point

R.V.COLLEGE OF ENGINEERING Page 117

Page 118: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

3.4 x 1038 numberdouble Yes System.Double 5.0 x 10-324

to 1.7 x 10308

64-bit floating point number

bool Yes System.Boolean True or False

Represents truth or falsity

decimal Yes System.Decimal 1 to 1028 96-bit signed numberstring Yes System.String Limited by

system memory

Represents a set of Unicode characters

object Yes System.Object Anything(all types excluding interfaces) derive from object

The base class of all types in the .NET universe.

The relationship between the core system types is shown in the figure 1.1. From

this diagram, we can see that all the types are ultimately derived from

System.Object. Since the data types like int are simply shorthand notations for the

corresponding system type (like System.Int32), the following statements are valid –

Console.WriteLine(25.GetHashCode());

Console.WriteLine(32.GetType().BaseType()); etc.

We can see that, though C# defines a number of data types, only a subset of the

whole set of data types are compliant with the rules of CLS. So, while building user-

defined types (like class, structures), we should use only CLS-compliant types. And

also, we should avoid using unsigned types as public member of user-defined type.

By doing this, our user-defined type (class, enumeration, structure etc) can be

understood by any language in .NET framework.

Experimenting with the System Data Types

From the Figure 3.1, it is clear that C# data types are alias names for a related

structure in the System namespace, and hence derived from System.ValueType.

The purpose of System.ValueType is to override the virtual methods defined by

R.V.COLLEGE OF ENGINEERING Page 118

Page 119: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

System.Object to work with value-based v/s reference-based semantics. Since data

types are value types, the comparison of two variables will be based on their

internal value, but not the reference:

System.Int32 a=20;

int b=20;

if(a==b) //comparison based on value

Console.WriteLine(“Same!!”);

R.V.COLLEGE OF ENGINEERING Page 119

Object

Type

String

Array

Exception

Delegate

MulticastDelegate

Byte

Boolean

Char

Decimal

Double

Int16

Int64

Int32

UInt16

UInt32

UInt64

Void

DateTime

Guid

TimeSpan

SByte

Single

ValueType

Any type that derives from

ValueType is a structure not a

class

Enumerations and Structures

Page 120: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

R.V.COLLEGE OF ENGINEERING Page 120

Page 121: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Fig. 1.1 The hierarchy of System Types

Basic Numerical Members

To understand the numerical types in C#, consider the following example –

Program 1.8

using System;

class Test

{

public static void Main()

{

System.UInt16 a=30000;

Console.WriteLine("Max value for UInt16: {0}", UInt16.MaxValue); //65535

Console.WriteLine("Min value for UInt16: {0}", UInt16.MinValue); //0

Console.WriteLine("value of UInt16: {0}", a); //30000

Console.WriteLine("The type is: {0}", a.GetType().ToString()); //System.UInt16

ushort b=12000;

Console.WriteLine("Max value for ushort: {0}", ushort.MaxValue); //65535

R.V.COLLEGE OF ENGINEERING Page 121

Page 122: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Console.WriteLine("Min value for ushort: {0}", ushort.MinValue); //0

Console.WriteLine("value of ushort: {0}", b); //12000

Console.WriteLine("The type is: {0}", b.GetType().ToString()); //System.UInt16

Console.WriteLine("double.Epsilon: {0}", double.Epsilon);

//4.94065645841247E-324

Console.WriteLine("double.PositiveInfinity: {0}", double.PositiveInfinity);

//Infinity

Console.WriteLine("double.NegativeInfinity: {0}", double.NegativeInfinity);

//-Infinity

Console.WriteLine("double.MaxValue: {0}", double.MaxValue);

// 1.79769313486232E+308

Console.WriteLine("double.MinValue: {0}", double.MinValue);

//-1.79769313486232E+308

}

}

Members of System.Boolean

In C#, for Boolean data, we have to assign any one value true or false. We can not

use the numbers like -1, 0, 1 etc. as we do in C++. The usage of bool data is shown

in Program 1.9.

Members of System.Char

All the .NET-aware languages map textual data into the same underlying types viz

System.String and System.Char, both are Unicode. The System.Char type provides

several methods as shown in the following example –

R.V.COLLEGE OF ENGINEERING Page 122

Page 123: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Program 1.9

using System;

class Test

{

public static void Main()

{

bool b1=true;

bool b2=false;

Console.WriteLine("{0}", bool.FalseString); //False

Console.WriteLine("{0}", bool.TrueString); //True

Console.WriteLine("{0}, {1}", b1, b2); //True, False

Console.WriteLine("{0}", char.IsDigit('P')); //False

Console.WriteLine("{0}", char.IsDigit('9')); //True

Console.WriteLine("{0}", char.IsLetter("10", 1)); //False

Console.WriteLine("{0}", char.IsLetter("1a", 1)); //True

Console.WriteLine("{0}", char.IsLetter('p'));//True

Console.WriteLine("{0}", char.IsWhiteSpace("Hello World", 5)); //True

Console.WriteLine("{0}", char.IsWhiteSpace("Hello World", 6)); //False

Console.WriteLine("{0}", char.IsLetterOrDigit('?')); //False

Console.WriteLine("{0}", char.IsPunctuation('!')); //True

Console.WriteLine("{0}", char.IsPunctuation('<')); //False

Console.WriteLine("{0}", char.IsPunctuation(',')); //True

R.V.COLLEGE OF ENGINEERING Page 123

Page 124: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

}

}

Parsing Values from String Data

.NET data types provide the ability to generate a variable of their underlying type

given a textual equivalent. This technique is called as parsing. This is helpful when

we need to convert user input data into a numerical value. Consider the following

program –

Program 1.10

using System;

class Test

{

public static void Main()

{

bool b=bool.Parse("True");

Console.WriteLine("Value of bool is:{0}", b); //True

double d=double.Parse("99.457");

Console.WriteLine("Value of double is:{0}", d); //99.457

int i=int.Parse("8");

Console.WriteLine("Value of int is:{0}", i); //8

R.V.COLLEGE OF ENGINEERING Page 124

Page 125: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

char c=char.Parse("w");

Console.WriteLine("Value of char is:{0}", c); //w

}

}

1.21 Boxing and Un-boxing

We know that .NET defines two broad categories of types viz. value types and

reference types. Sometimes, we may need to convert variables of one category to

the variables of other category. For doing so, .NET provides a mechanism called

boxing.

Boxing can be defined as the process of explicitly converting a value type

into a reference type.

When we box a variable, a new object is allocated in the heap and the value

of variable is copied into the object.

For example,

int p=20;

object ob=p; //box the value type p into an object reference

The operation just opposite to boxing is called as unboxing.

Unboxing is the process of converting the value held in the object reference

back into a corresponding value type.

When we try to unbox an object, the compiler first checks whether is the

receiving data type is equivalent to the boxed type or not.

If yes, the value stored in the object is copied into a variable in the stack.

R.V.COLLEGE OF ENGINEERING Page 125

Page 126: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

If we try to unbox an object to a data type other than the original type, an

exception called InvalidCastException is generated.

For example,

int p=20;

object ob=p;

--------

-------

int b=(int)ob; // unboxing successful

string s=(string)ob;// InvalidCastException

Generally, there will few situations in which we need boxing and/or unboxing. In

most of the situations, C# compiler will automatically boxes the variables. For

example, if we pass a value type data to a function having reference type object as

a parameter, then automatic boxing takes place. Consider the following program –

Program 1.11

using System;

class Test

{

public static void MyFunc(object ob)

{

Console.WriteLine(ob.GetType());

Console.WriteLine(ob.ToString());

Console.WriteLine(((int)ob).GetTypeCode());

}

R.V.COLLEGE OF ENGINEERING Page 126

Page 127: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

public static void Main()

{

int x=20;

MyFunc(x);

}

}

The output would be –

System.Int32

20

Int32

NOTE:

1. Boxing and unboxing takes some processing time. So, it must be used only

when needed.

2. When we pass custom (user defined) structures/enumerations into a method

taking generic System.Obejct parameter, we need to unbox the parameter to

interact with the specific members of the structure/enumeration. We will

study this later in-detail.

1.22 Summary

This section revealed the value types and reference types in .NET framework. We

have seen how value types and reference types behave in various situations. We

have also discussed the basic methods of System.Object class and how to override

them according to our need in the program. The boxing and un-boxing techniques

R.V.COLLEGE OF ENGINEERING Page 127

Page 128: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

allow the programmer to switch between value types and reference types in the

program.

1.23 Keywords

Value Type and Reference Type

Stack area and Heap area

Shallow Copy and Deep Copy

Members of System.Boolean, System.Char and numeric members

Parsing values from Sting type

Boxing and unboxing

1.24 Exercises

1. Write a program to illustrate the difference between passing reference types by reference

and by value.

2. Bring out the difference between value types and reference types.

3. How do you override ToString() method of System.Object class? Explain with a program.

4. Explain the concept of GetHashCode() method.

5. Draw a diagram to depict the hierarchy of System types and explain.

6. What is boxing and unboxing? Explain with an example for each.

7. What is the output printed by the following code segment and why?

struct Point

{

public int x, y;

R.V.COLLEGE OF ENGINEERING Page 128

Page 129: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

public Point(int x, int y)

{

this.x=x ;

this.y=y ;

}

}

Point p=new Point(10,10) ;

object obj=p ;

p.x=20;

Console.WriteLine(“p.x={0}”, p.x);

Console.WriteLine("obj.x={0}", ((Point)obj).x) ;

Module 2

Unit 2

CONTENTS:

2.13 Objectives2.14 Introduction2.15 Defining Custom Class Methods2.16 Understanding Static Methods2.17 Methods Parameter Modifiers2.18 Array Manipulation in C#2.19 String Manipulation in C#2.20 C# Enumerations2.21 Defining Structures in C#2.22 Defining Custom Namespaces2.23 Summary2.24 Keywords2.25 Exercises

R.V.COLLEGE OF ENGINEERING Page 129

Page 130: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

2.1 Objectives

At the end of this lesson, students will understand the following tasks in detail:

Defining User-defined/Custom methods for a class

Static Members (Data and Method) of a class

The parameter modifiers like out, params, ref

Members of Array and String class

Manipulation of Arrays and Strings

C# enumeration and structures

Concept of user-defined/custom namespaces

2.13Introduction

In all the previous units, we have discussed basic concepts of C# programming

language. Here, we will continue with understanding how to define own methods for

a class, the concept of static members of a class, how to define our own namespace

based on the requirements and so on. Also, we will elaborate the value types of C#

viz. structure and enumeration types.

2.14Defining Custom Class Methods

In C#, every data and a method must be a member of a class or structure. That is,

we can not have global data or method. The methods in C# may or may not take

parameters and they may or may not return a value. Also, custom methods (user

defined methods) may be declared non-static (instance level) or static (class level).

Method Access Modifiers

R.V.COLLEGE OF ENGINEERING Page 130

Page 131: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Every method in C# specifies its level of accessibility using following access

modifiers:

Access Modifiers Meaningpublic Method is accessible from an object or any

subclass.private Method is accessible only by the class in which it

is defined. private is a default modifier in C#.protected Method is accessible by the defining class and all

its sub-classes.internal Method is publicly accessible by all types in an

assembly, but not outside the assembly.protected internal Method’s access is limited to the current assembly

or types derived from the defining class in the current assembly.

2.15Understanding Static Methods

A method can be declared as static. When a method is static, it can be invoked

directly from the class level, without creating an object. This is the reason for

making Main() function to be static. The another example is WriteLine() method. We

will directly use the statement Console.WriteLine() without creating an object of

Console class. Consider the following program:

Program 2.1

using System;

class Test

{

public static void disp()

{

Console.WriteLine(“hello”);

R.V.COLLEGE OF ENGINEERING Page 131

Page 132: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

}

public static void Main()

{

Test.disp(); //calling method using class name itself

}

}

Defining static Data

Normally, we will define a set of data members for a class. Then every object of that

class will have separate copy of each of those data members. For example,

class Test

{

public int p;

}

-------

------

Test t1=new Test();

t1.p=10;

Test t2= new Test();

t2.p=15;

Here, the objects t1 and t2 will be having separate copy of the variable p.

On the other hand, static data is shared among all the objects of that class. That is,

for all the objects of a class, there will be only one copy of static data. For example,

R.V.COLLEGE OF ENGINEERING Page 132

Page 133: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Program 2.2

using System;

class Test

{

public static int p=0;

public int incr()

{

return ++p;

}

public static void Main()

{

Test t1=new Test();

Test t2=new Test();

Console.WriteLine("p= {0}", t1.incr()); //1

Console.WriteLine("p= {0}", t2.incr()); //2

Console.WriteLine("p= {0}", t1.incr()); //3

}

}

2.16Method Parameter Modifiers

R.V.COLLEGE OF ENGINEERING Page 133

Page 134: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Normally methods will take parameter. While calling a method, parameters can be

passed in different ways. C# provides some parameter modifiers as shown –

Parameter Modifier Meaning(none) If a parameter is not attached with any modifier,

then parameter’s value is passed to the method. This is the default way of passing parameter. (call-by-value)

out The output parameters are assigned by the called method.

ref Reference to a parameter is passed to a method. (call-by-reference)

params This modifier will allow to send many number of parameters as a single parameter. Any method can have only one params modifier and it should be the last parameter for the method.

The Default Parameter Passing Behavior

By default, the parameters are passed to a method by value. So, the changes made

for parameters within a method will not affect the actual parameters of the calling

method. Consider the following example –

Program 2.3

using System;

class Test

{

public static void swap(int x, int y)

{

int temp=x;

x=y;

y=temp;

R.V.COLLEGE OF ENGINEERING Page 134

Page 135: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

}

public static void Main()

{

int x=5,y=20;

Console.WriteLine("Before: x={0}, y={1}", x, y);swap(x,y);

Console.WriteLine("After: x={0}, y={1}", x, y);

}

}

The output would be –

Before: x=5, y=20

After : x=5, y=20

The out Keyword

In some of the methods, we need to return a value to a calling method. Instead of

using return statement, C# provides a modifier for a parameter as out. The usage of

out can be better understood by the following example –

Program 2.4

using System;

class Test

R.V.COLLEGE OF ENGINEERING Page 135

Page 136: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

{

public static void add(int x, int y, out int z)

{

z=x+y;

}

public static void Main()

{

int x=5,y=20, z;

add(x, y, out z);

Console.WriteLine("z={0}", z); //z=25

}

}

The out parameter is certainly useful when we need more values to be returned

from a method. Consider the following example –

Program 2.5

using System;

class Test

{

public static void MyFun(out int x, out string s)

{

x=5;

R.V.COLLEGE OF ENGINEERING Page 136

Page 137: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

s="Hello, how are you?";

}

public static void Main()

{

int a;

string str;

MyFun(out a, out str);

Console.WriteLine("a={0}, str={1}", a, str);

}

}

The output would be –

a=5, str=”Hello, how are you?

The C# ref Keyword

Whenever we want the changes made in method to get affected in the calling

method, then we will go for call by ref. Following are the differences between output

and reference parameters:

The output parameters do not need to be initialized before sending to called

method. Because it is assumed that the called method will fill the value for

such parameter.

The reference parameters must be initialized before sending to called

method. Because, we are passing a reference to an existing type and if we

don’t assign an initial value, it would be equivalent to working on NULL

pointer.

R.V.COLLEGE OF ENGINEERING Page 137

Page 138: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Program 2.6

using System;

class Test

{

public static void Main()

{

string s="hello";

Console.WriteLine("Before:{0}",s);

MyFun(ref s);

Console.WriteLine("After:{0}",s);

}

public static void MyFun(ref string s)

{

s=s.ToUpper();

}

}

The output would be –

Before: hello

After: HELLO

The C# params Keyword

R.V.COLLEGE OF ENGINEERING Page 138

Page 139: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

The params keyword of C# allows us to send many numbers of arguments as a

single parameter. To illustrate the use of params, consider the following example –

Program 2.7

using System;

class Test

{

public static void MyFun(params int[] arr)

{

for(int i=0; i<arr.Length; i++)

Console.WriteLine(arr[i]);

}

public static void Main()

{

int[] a=new int[3]{5, 10, 15};

int p=25, q=102;

MyFun(a);

MyFun(p, q);

}

R.V.COLLEGE OF ENGINEERING Page 139

Page 140: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

}

The output would be –

5 10 15 25 102

From the above example, we can observe that for params parameter, we can pass

an array or individual elements.

We can use params even when the parameters to be passed are of different types,

as shown in the following program –

Program 2.8

using System;

class Test

{

public static void MyFun(params object[] arr)

{

for(int i=0; i<arr.Length; i++)

{

if(arr[i] is Int32)

Console.WriteLine("{0} is an integer", arr[i]);

else if(arr[i] is string)

Console.WriteLine("{0} is a string", arr[i]);

else if(arr[i] is bool)

Console.WriteLine("{0} is a boolean", arr[i]);

}

R.V.COLLEGE OF ENGINEERING Page 140

Page 141: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

}

public static void Main()

{

int x=5;

string s="hello";

bool b=true;

MyFun(b, x, s);

}

}

The output would be –

True is a Boolean

5 is an integer

hello is a string

Passing Reference Types by Value and Reference

Till now, we have seen how to pass a parameter to methods by value and by using

ref. In the previous examples, we have passed value type variables as parameters

to methods (Just recollect that there are two types of variables value type like int,

char, string, structure etc. and reference type like class, delegates). Now we will see

what happens when reference type variables (i.e. objects of class) are passed as

parameters. Consider the program –

Program 2.9

R.V.COLLEGE OF ENGINEERING Page 141

Page 142: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

using System;

class Person

{

string name;

int age;

public Person(string n, int a)

{

name=n;

age=a;

}

public static void CallByVal(Person p)

{

p.age=66;

p=new Person("Shyamu", 25);

}

public static void CallByRef(ref Person p)

{

p.age=55;

p=new Person("Shyamu", 20);

}

public void disp()

R.V.COLLEGE OF ENGINEERING Page 142

Page 143: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

{

Console.WriteLine("{0} {1}", name, age);

}

public static void Main()

{

Person p1=new Person("Ramu", 30);

p1.disp();

CallByVal(p1);

p1.disp();

CallByRef(ref p1);

p1.disp();

}

}

The output would be –

Ramu 30

Ramu 66

Shyamu 20

In the Main() function, we have created an object p1 of Person class. Memory will be

allocated to p1 from heap as p1 is of reference type (object of a class). Now, the

display will be –

Ramu 30

R.V.COLLEGE OF ENGINEERING Page 143

Page 144: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Now we are passing p1 to the function using call-by-value method. But, by nature,

p1 is of reference type. So, in the receiving end, the object p takes the reference of

p1. That means, the memory location for both p1 and p will be same. Thus, the

statement

p.age = 66;

will affect the original object p1. And hence the output will be –

Ramu 66

But, when we try to allocate new memory for p, the compiler will treat p as different

object and new memory is allocated from heap. Now onwards, p and p1 are

different.

Next, we are passing p1 using the modifier ref. This is nothing but call-by-reference.

Here also, the receiving object p will be a reference to p1. Since the parameter

passing technique used is call-by-reference, as per the definition, any changes in

method should affect the calling method. Thus, the statement

p= new Person(“Shyamu”, 20);

will affect the original object p1 and hence the output is –

Shyamu 20

NOTE: The important rule to be remembered is: “If a class type (reference

type) is passed by reference, the called method will change the values of

the object’s data and also the object it is referencing”.

R.V.COLLEGE OF ENGINEERING Page 144

Page 145: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

2.17Array Manipulation in C#

C# arrays look like that of C/C++. But, basically, they are derived from the base

class viz. System.Array. Array is a collection of data elements of same type, which

are accessed using numerical index. Normally, in C#, the array index starts with 0.

But it is possible to have an array with arbitrary lower bound using the static

method CreateInstance() of System.Array. Arrays can be single or multi-

dimensional. The declaration of array would look like –

int[ ] a= new int[10];

a[0]= 5;

a[1]= 14;

……….

string[ ] s= new string[2]{“Ramu”, “Shymu”};

int[ ] b={15, 25, 31, 78}; //new is missing. Still valid

In .NET, the members of array are automatically set to their respective default

value. For example, in the statement,

int[ ] a= new int[10];

all the elements of a are set to 0. Similarly, string array elements are set to null and

so on.

Array as Parameters and Return Values

Array can be passed as parameter to a method and also can be returned from a

method. Consider the following example –

R.V.COLLEGE OF ENGINEERING Page 145

Page 146: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Program 2.10

using System;

class Test

{

public static void disp(int[ ] arr) //taking array as parameter

{

for(int i=0;i<arr.Length;i++)

Console.WriteLine("{0} ", arr[i]);

}

public static string[ ] MyFun() //returning an array

{

string[ ] str={"Hello", "World"};

return str;

}

public static void Main()

{

int[ ] p=new int[ ]{20, 54, 12, -56};

disp(p);

string[ ] strs=MyFun();

foreach(string s in strs)

Console.WriteLine(s);

R.V.COLLEGE OF ENGINEERING Page 146

Page 147: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

}

}

The output would be –

20 54 12 -56 Hello World

Working with Multidimensional Arrays

There are two types of multi-dimensional arrays in C# viz. rectangular array and

jagged array. The rectangular array is an array of multiple dimensions and each

row is of same length. For example –

Program 2.11

using System;

class Test

{

public static void Main()

{

int[,] arr=new int[2,3]{{5, 7, 0}, {3, 1, 8}};

int sum=0;

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

for(int j=0;j<3;j++)

sum=sum+arr[i,j];

R.V.COLLEGE OF ENGINEERING Page 147

Page 148: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Console.WriteLine("Sum is {0}", sum);

}

}

The output would be –

Sum is 24

Jagged array contain some number of inner arrays, each of which may have unique

size. For example –

Program 2.12

using System;

class JaggedArray

{

public static int[][] JArr=new int[3][];

public static void Main()

{

int m, n, p, sum=0;

Console.WriteLine("Enter the sizes for 3 inner arrays:");

m=int.Parse((Console.ReadLine()).ToString());

n=int.Parse((Console.ReadLine()).ToString());

R.V.COLLEGE OF ENGINEERING Page 148

Page 149: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

p=int.Parse((Console.ReadLine()).ToString());

JArr[0]=new int[m];

JArr[1]=new int[n];

JArr[2]=new int[p];

Console.WriteLine("Enter the elements for array:");

for(int i=0;i<3;i++)

for(int j=0;j<JArr[i].Length;j++)

{

JArr[i][j]=int.Parse((Console.ReadLine()).ToString());

sum=sum+JArr[i][j];

}

Console.WriteLine("\nThe Sum is: {0}",sum);

}

}

The output would be –

Enter the sizes for 3 inner arrays:

2 3 2

Enter the elements for array:

1 2 3 4 5 6 7

The Sum is: 28

The System.Array Base Class

R.V.COLLEGE OF ENGINEERING Page 149

Page 150: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Every array in C# is derived from the class System.Array. This class defines number

of methods to work with arrays. Few of the methods are given below –

Member MeaningBinarySearch()

This static method searches a (previously sorted) array for a given item. If the array is composed of user-defined data types, the type in question must implement the IComparer interface to engage in a binary search.

Clear() This static method sets a range of elements in the array to empty values (0 for value types; null for reference types).

CopyTo() This method is used to copy elements from the source array into the destination array.

Length This read-only property is used to determine the number of elements in an array.

Rank This property returns the number of dimensions of the current array.

Reverse() This static method reverses the contents of a one-dimensional array.

Sort() This method sorts a one-dimensional array of intrinsic types. If the elements in the array implement the IComparer interface, we can also sort an array of user-defined data type .

Consider the following example to illustrate some methods and/or properties of

System.Array class –

Program 2.13

using System;

class Test

{

public static void Main()

{

R.V.COLLEGE OF ENGINEERING Page 150

Page 151: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

int[] arr=new int[5]{12, 0, 45, 32, 67};

Console.WriteLine("Array elements are :");

for(int i=0;i<arr.Length;i++)

Console.WriteLine("{0}\t", arr[i]);

Array.Reverse(arr);

Console.WriteLine("Reversed Array elements are :");

for(int i=0;i<arr.Length;i++)

Console.WriteLine("{0}\t", arr[i]);

Array.Clear(arr, 1, 3);

Console.WriteLine("Cleared some elements :");

for(int i=0;i<arr.Length;i++)

Console.WriteLine("{0}\t", arr[i]);

}

}

The Output would be –

Array elements are:

12 0 45 32 67

Reversed Array elements are:

67 32 45 0 12

R.V.COLLEGE OF ENGINEERING Page 151

Page 152: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Cleared some elements:

67 0 0 0 12

2.18String Manipulation in C#

Till now, we have used string key word as a data type. But truly speaking, string is

an alias type for System.String class. This class provides a set of methods to work

on strings. Following is a list of few such methods –

Member MeaningLength This property returns the length of the current string.

Contains() This method is used to determine if the current string object contains a specified string.

Concat() This static method of the String class returns a new string that is composed of two discrete strings.

CompareTo() Compares two strings.Copy() Returns a fresh new copy of an existing string.

Format() This static method is used to format a string literal using other primitives (i.e., numerical data and other strings) and the {0} notation examined earlier in this chapter.

Insert() This method is used to receive a copy of the current string that contains newly inserted string data.

PadLeft()PadRight()

These methods return copies of the current string that has been padded with specific data.

Remove()Replace()

Use these methods to receive a copy of a string, with modifications (characters removed or replaced).

Substring() This method returns a string that represents a substring of the current string.

ToCharArray()

This method returns a character array representing the current string.

ToUpper()ToLower()

These methods create a copy of a given string in uppercase or lowercase.

Consider the following example –

R.V.COLLEGE OF ENGINEERING Page 152

Page 153: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Program 2.14

using System;

class Test

{

public static void Main()

{

System.String s1="This is a string";

string s2="This is another string";

if(s1==s2)

Console.WriteLine("Same strings");

else

Console.WriteLine("Different strings");

string s3=s1+s2;

Console.WriteLine("s3={0}",s3);

for(int i=0;i<s1.Length;i++)

Console.WriteLine("Char {0} is {1}\n",i, s1[i]);

Console.WriteLine("Cotains 'is'?: {0}", s1.Contains("is"));

R.V.COLLEGE OF ENGINEERING Page 153

Page 154: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Console.WriteLine(s1.Replace('a',' '));

}

}

The output would be –

Different strings

s3=This is a stringThis is another string

Char 0 is T Char 1 is h Char 2 is i Char 3 is s

Char 4 is Char 5 is I Char 6 is s Char 7 is

Char 8 is a Char 9 is Char 10 is s Char 11 is t

Char 12 is r Char 13 is I Char 14 is n Char 15 is g

Cotains 'is'?: True

This is string

Escape Characters and “Verbatim Strings”

Just like C, C++ and Java, C# also provides some set of escape characters as shown

Character Meaning\’ Inserts a single quote into a string literal.\" Inserts a double quote into a string literal.\\ Inserts a backslash into a string literal. This can be quite helpful when

defining file paths.\a Triggers a system alert (beep). For console applications, this can be an

audio clue to the user.\b Triggers a backspace.\f Triggers a form feed.\n Inserts a new line (on Win32 platforms).\r Inserts a carriage return.\t Inserts a horizontal tab into the string literal\u Inserts a Unicode character into the string literal.

R.V.COLLEGE OF ENGINEERING Page 154

Page 155: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

\v Inserts a vertical tab into the string literal\0 Represents NULL character.

In addition to escape characters, C# provides the @-quoted string literal notation

named as verbatim string. Using this, we can bypass the use of escape characters

and define our literals. Consider the following example –

Program 2.15

using System;

class Test

{

public static void Main()

{

string s1="I said, \"Hi\"";

Console.WriteLine("{0}",s1);

s1="C:\\Notes\\DotNet\\Chapter3.doc";

Console.WriteLine("{0}",s1);

string s2=@"C:\Notes\DotNet\Chapter3.doc";

Console.WriteLine("{0}",s2);

}

}

The output would be –

I said, "Hi"

R.V.COLLEGE OF ENGINEERING Page 155

Page 156: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

C:\Notes\DotNet\Chapter3.doc

C:\Notes\DotNet\Chapter3.doc

Using System.Text.StringBuilder

In the previous examples, we tried to change the content of strings using various

methods like Replace(), ToUpper() etc. But, the value of a string cannot be modified

once it is established. The methods like Replace() may seems to change the content

of the string, but actually, those methods just output a copy of the string and the

original string remains the same. For example –

string s1=”Hello”;

Console.WriteLine(“s1={0}”, s1); //Hello

string s2=s1.ToUpper();

Console.WriteLine(“s2={0}”, s2); //HELLO

Console.WriteLine(“s1={0}”, s1); //Hello

Thus, whenever we want to modify a string, we should have a new string to store

the modified version. That is, every time we have to work on a copy of the string,

but not the original. To avoid this in-efficiency, C# provides a class called

StringBuilder contained in the namespace System.Text. Any modification on an

instance of StringBuilder will affect the underlying buffer itself. Consider the

following example –

Program 2.16

using System;

using System.Text;

R.V.COLLEGE OF ENGINEERING Page 156

Page 157: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

class Test

{

public static void Main()

{

StringBuilder s1= new StringBuilder("Hello");

s1.Append(" World");

Console.WriteLine("{0}",s1);

string s2=s1.ToString().ToUpper();

Console.WriteLine("{0}",s2);

}

}

The output would be –

Hello World

HELLO WORLD

2.19C# Enumerations

When number of values taken by a type is limited, it is better to go for symbolic

names rather than numeric values. For example, the marital status of a person can

be any one of Married, Widowed, Unmarried, Divorced. To have such symbolic

names, C# provides enumerations –

enum M_Status

{

R.V.COLLEGE OF ENGINEERING Page 157

Page 158: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Married, //0

Widowed, //1

Unmarried, //2

Divorced //3

}

In enumeration, the value for first symbolic name is automatically initialized to 0

and second to 1 etc. If we want to give any specific value, we can use –

enum M_Status

{

Married =125,

Widowed, //126

Unmarried, //127

Divorced //128

}

Or

enum M_Status

{

Married =125,

Widowed=0,

Unmarried=23,

Divorced=12

}

R.V.COLLEGE OF ENGINEERING Page 158

Page 159: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

By default, the storage type used for each item of enumeration is System.Int32. We

can change it, if we wish –

enum M_Status: byte

{

Married =125,

Widowed=0,

Unmarried=23,

Divorced=12

}

Enumerations can be used as shown below –

Program 2.17

using System;

class Test

{

enum M_Status: byte

{

Married =125,

Widowed=0,

Unmarried=23,

Divorced=12

}

R.V.COLLEGE OF ENGINEERING Page 159

Page 160: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

public static void Main()

{

M_Status p1, p2;

p1=M_Status.Married;

p2=M_Status.Divorced;

if(p1==M_Status.Married)

Console.WriteLine("p1 is married"); // p1 is married

if(p2==M_Status.Divorced)

Console.WriteLine("p2 is {0}", M_Status.Divorced); //p2 is Divorced

}

}

The System.Enum Base Class

The C# enumerations are derived from System.Enum class. This base class defines

some methods for working with enumerations.

Member MeaningFormat() Converts a value of a specified enumerated type to its

equivalent string representation according to the specified format

GetName()GetNames()

Retrieves a name (or an array containing all names) for the constant in the specified enumeration that has the specified value

GetUnderlyingType() Returns the underlying data type used to hold the values for a given enumeration

GetValues() Retrieves an array of the values of the constants in a specifiedEnumeration

IsDefined() Returns an indication of whether a constant with a specified

R.V.COLLEGE OF ENGINEERING Page 160

Page 161: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

valueexists in a specified enumeration

Parse() Converts the string representation of the name or numeric value of one or more enumerated constants to an equivalent enumerated object

Consider the following example to illustrate some of the methods of Enum class.

Program 2.18

using System;

class Test

{

enum M_Status

{

Married ,

Widowed,

Unmarried,

Divorced

}

public static void Main()

{

Console.WriteLine(Enum.GetUnderlyingType(typeof(M_Status)));

Array obj =Enum.GetValues(typeof(M_Status));

R.V.COLLEGE OF ENGINEERING Page 161

Page 162: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Console.WriteLine("This enum has {0} members", obj.Length);

foreach(M_Status p in obj)

{

Console.WriteLine("String name: {0}", p.ToString());

Console.WriteLine("int: ({0}),", Enum.Format(typeof(M_Status), p, "D"));

Console.WriteLine("hex: ({0}),", Enum.Format(typeof(M_Status), p, "X"));

}

if(Enum.IsDefined(typeof(M_Status), "Widowed"))

Console.WriteLine("Widowed is defined");

M_Status p1 = (M_Status)Enum.Parse(typeof(M_Status), "Divorced");

Console.WriteLine("p1 is {0}", p2.ToString());

M_Status p2=M_Status.Married;

if(p1<p2)

Console.WriteLine(“p1 has less value than p2”);

else

Console.WriteLine(“p1 has more value than p2”);

}

}

The output would be –

System.Int32

R.V.COLLEGE OF ENGINEERING Page 162

Page 163: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

This enum has 4 members

String name: Married int: (0) hex: (00000000)

String name: Widowed int: (1) hex: (00000001)

String name: Unmarried int: (2) hex: (00000002)

String name: Divorced int: (3) hex: (00000003)

Widowed is defined

p1 is Divorced

p1 has more value than p2

2.20Defining Structures in C#

In C#, structures behave similar to class, except that memory structures will be

allocated in stack area, whereas for class memory will be allocated from heap area.

Structures can have member data, member methods, constructors (only

parameterized) and they can implement interfaces. Structure in C# is directly

derived from System.ValueType. We can implement boxing and unboxing on

structures just like as we do for any intrinsic data types.

Consider the following example –

Program 2.19

using System;

struct EMP

R.V.COLLEGE OF ENGINEERING Page 163

Page 164: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

{

public int age;

public string name;

public EMP(int a, string n)

{

age=a;

name=n;

}

public void disp()

{

Console.WriteLine("Name ={0}, Age ={1}", name, age);

}

}

class Test

{

public static void Main()

{

EMP e=new EMP(25, "Ramu");

e.disp();

object ob=e; //boxing

MyFun(ob);

}

R.V.COLLEGE OF ENGINEERING Page 164

Page 165: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

public static void MyFun(object obj)

{

EMP t=(EMP)obj; //unboxing

Console.WriteLine("After boxing and un-boxing:");

t.disp();

}

}

The output would be –

Name =Ramu, Age =25

After boxing and un-boxing:

Name =Ramu, Age =25

2.21 Defining Custom Namespaces

In the programs we discussed till now, we have used namespaces like System,

System.Text etc. These are existing namespaces in the .NET framework. We can

define our own namespace i.e. user-defined namespace (or custom namespace).

Whenever we want to group similar classes into a single entity, we can define a

namespace.

Assume we need to develop a program to show the features of several vehicles like

car, bus and bike. Then, the classes for all these vehicles can be put under a

namespace like –

R.V.COLLEGE OF ENGINEERING Page 165

Page 166: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

namespace Vehicle

{

public class Car

{

//members of Car class

}

public class Bus

{

//members of Bus class

}

public class Bike

{

//members of Bike class

}

}

Now, the namespace Vehicle acts as a container for all these classes. If we want to

create an object of any of these classes in any other application, we can simply

write –

using System;

using Vehicle; //note this

class Test

R.V.COLLEGE OF ENGINEERING Page 166

Page 167: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

{

public static void Main()

{

Car c=new Car();

-------

-------

}

}

Resolving Name Clashes Across Namespaces

There may be situation where more than one namespace contains the class with

same name. For example, we may have one more namespace like –

namespace MyVehicle

{

public class Car

{

//members of Car class

}

--------

}

When we include the namespaces MyVehicle and Vehicle, and try to create an

object of Car class, we will get an error. To avoid this, we will use dot operator for

combining namespace name and class name. For example –

using System;

R.V.COLLEGE OF ENGINEERING Page 167

Page 168: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

using Vehicle;

using MyVehicle;

class Test

{

public static void Main()

{

// Car c=new Car(); Error!!! name conflict

Vehicle.Car c1=new Vehicle.Car();

MyVehicle.Car c2=new MyVehicle.Car();

---------

}

}

Defining Namespace Aliases

The ambiguity in the namespaces can also be resolved using alias names as shown

using System;

using Vehicle;

using MyVehicle;

using MyCar=MyVehicle.Car;

class Test

{

R.V.COLLEGE OF ENGINEERING Page 168

Page 169: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

public static void Main()

{

Car c1=new Car();

MyCar c2=new MyCar();

---------

}

}

Nested Namespaces

We can nest one namespace within the other also. For example –

namespace Vehicle

{

namespace MyVehicle

{

-----

-----

}

}

Or

namespace Vehicle.MyVehicle

{

-------

}

R.V.COLLEGE OF ENGINEERING Page 169

Page 170: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

2.22 Summary

This section brought out the salient features of C# value types like structures and

enumerations. We have discussed the concept of static methods, the access-

specifiers/modifiers for the methods of a class, the different keywords used for

passing parameters to methods etc. Also, we understood how to define our own

namespace rather than using the in-build namespaces.

2.23 Keywords

Access Modifiers: public, private, protected, internal, protected internal

Static Data and Static Method

Parameter modifiers: out, ref, params

Passing reference types by value and by reference

System.Array class and its members

Multidimensional Array: Rectangular and Jagged arrays

System.String class and its members

Escape characters and Verbatim Strings

System.Text.StringBuilder class and its members

System.Enum base class and its members

Structures (struct)

Namespaces: Aliases and nested

2.24 Exercises

8. What do you understand by ‘params’ method of parameter passing? Give an

example.

9. Explain the C# static methods and static data with suitable examples.

R.V.COLLEGE OF ENGINEERING Page 170

Page 171: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

10.Using the methods in System.String class, design a C# method which replaces

all occurrences of the word “computer” with “COMPUTER”.

11.What is the difference between System.String and System.Text.StringBuilder?

Explain with relevant code some of the features of StringBuilder class.

12.Write a C# program to design a structure Student<USN, Name, Marks, Branch>.

Here, Branch is of type Enum with members MCA, MBA, MTech. Add appropriate

constructor and also a method to hike the marks by 10% to only MCA students.

Show creation of some Student objects and the way to call these methods.

13.Explain various method parameter modifiers used in C#.

14.Design a C# class called Matrix containing an integer matrix as a member and

methods to

(i) read the elements of the matrix from the keyboard.

(ii) Find the addition of two matrices.

(iii) Find the product of two matrices.

(iv) Find the subtraction of two matrices.

(v) To print the elements in the matrix form.

Write a Main() method to call all these methods and to print all the three

matrices.

15.Write a program to count the number of objects created for a class.

16.What are jagged arrays? Write a program to find sum of elements in a jagged

array of 3 inner arrays.

Module 2

Unit 3

CONTENTS:

R.V.COLLEGE OF ENGINEERING Page 171

Page 172: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

1.28 Objectives3.2 Introduction

3.3Formal Definition of the C# Class

3.4Definition the “Default Public Interface” of a Type

3.5Recapping the Pillars of OOP

3.6The First Pillars: C#’s Encapsulation Services

3.7Pseudo Encapsulation: Creating Read-Only Fields

3.8Summary

3.9 Keywords

3.10 Exercises

3.1 Objectives

At the end of this lesson, the students will understand the following tasks in detail:

The basic concepts of oops

The method overloading, calling base class constructor through derived class

constructor

The two ways of encapsulation: traditional accessors and mutators and class

properties

The read-only/write-only/static properties

Read only fields

3.15Introduction

The previous units revealed the programming fundamentals of C#. Since C# is an

object oriented programming (OOP) language, we need to explore the OOPs

properties (that is encapsulation, inheritance and polymorphism) with respect to

C#. In this unit, we will discuss the basic concepts of OOPs in brief, and the

R.V.COLLEGE OF ENGINEERING Page 172

Page 173: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

encapsulation in detail. The other two concepts viz. inheritance and polymorphism

will be explored in next unit.

3.16Formal Definition of C# class

Class is a basis of OOPs. A class can be defined as a user-defined data type (UDT)

that is composed of data (or attributes) and functions (or methods) that act on this

data. In OOPs, we can group data and functionality into a single UDT to model a

real-world entity.

A C# class can define any number of constructors. Constructor is a special type of

method called automatically when object gets created. They are used to provide

initial values for some attributes. The programmer can define default constructor to

initialize all the objects with some common state. Custom or parameterized

constructors can be used to provide different states to the objects when they get

created. The general form of a C# class may look like –

class class_name

{

//data members

//constructors

//methods

}

Understanding Method Overloading

A class can have more than one method with a same name only if number and/or

type of parameters are different. Such methods are known as overloaded

methods. For example –

R.V.COLLEGE OF ENGINEERING Page 173

Page 174: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

// Example for overloaded constructors

class Employee

{

public Employee() //default constructor

{ }

public Employee(string name, int EmpID, float BasicSal)

{

//some code

}

}

// overloaded member-methods: number of arguments are different

class Triangle

{

public float Draw(float height, float base) //two arguments

{

//some code

}

public float Draw(float sideA, float sideB, float sideC) //3 args

{

//some code

}

}

// overloaded member-methods: type of arguments are different

R.V.COLLEGE OF ENGINEERING Page 174

Page 175: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

class Shape

{

public float Area(float height, float base)

{

//some code

}

public int Area(int a, int b)

{

//some code

}

}

// overloading can not be done only based on return-type

class Shape

{

//error!!!

public float Area(float height) //one parameter of type float

{

//some code

}

public int Area(float a ) //one parameter of type float

{

//some code

}

}

R.V.COLLEGE OF ENGINEERING Page 175

Page 176: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Self-Reference in C#

The key-word this is used to make reference to the current object i.e. the object

which invokes the function-call. For example –

class Employee

{

string name;

int eId;

public Employee(string name, int EmpID)

{

this.name=name;

this.eId=EmpID;

}

}

Note that the static member functions of a class can not use this keyword as static

methods are invoked using class name but not the object.

Forwarding Constructor Calls using “this”

Using this keyword, we can force one constructor to call another constructor during

constructor call. This will help us to avoid redundancy in member initialization logic.

R.V.COLLEGE OF ENGINEERING Page 176

Page 177: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Consider that there is a class called IDGenerator containing a static method to

generate employee id based on some pre-defined criteria like department and

designation of employee. The application may be having two situations: (a) provide

an employee id at the time of object creation, and (b) the employee id must be

generated from IDGenerator class. But the parameter like name of the employee is

provided during object creation itself. In such a situation, to avoid code-

redundancy, we may use this keyword to forward one constructor call to other as

shown below –

class IDGenerator

{

static int id;

public static int GetEmpID()

{

//code for generating an employee id viz id

return id;

}

}

class Employee

{

string name;

int eID;

float BasicSal;

public Employee(string n, int EmpID, float b)

R.V.COLLEGE OF ENGINEERING Page 177

Page 178: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

{

this.name=n; //either use this

this.eID=EmpID;

BasicSal=b; //or not use this

}

/ * GetEmpID() method is called first to generate employee-id and then the construct call is forwarded to the above constructor */

public Employee(string n): this(n, IDGenerator.GetEmpID(), 0.00)

{ }

public static void Main()

{

//direct call for constructor with three arguments

Employee e1=new Employee(“Ramu”, 111, 12000.00);

/* call for constructor with single arguments which in-turn calls constructor with three arguments later */

Employee e2=new Employee(“Shyamu”);

-------------------

}

}

In the above example, if we would have not forwarded the constructor call, then we

would need to write redundant code in the second constructor like –

R.V.COLLEGE OF ENGINEERING Page 178

Page 179: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

public Employee(string n)

{

this.name=n;

this.eID=IDGenerator.GetEmpID();

this.BasicSal=0.00;

}

Thus, using this keyword to forward constructor call, we are avoiding code

redundancy.

3.17Defining the “Default Public Interface” of a Type

The term default public interface refers to the set of public members (data or

method) that are directly accessible from an object. That means, the default public

interface is any item declared in the class with the keyword public. In C#, the

default public interface of a class may be any of the following:

Methods : Named units that model some behavior of a class

Properties : Accessor and mutator functions

Public data : A data member which is public (though it is not good

to use, C# provides if programmer needs)

Apart from above items, default public interface may include user defined event,

delegates and nested types.

Specifying Type Visibility: Public and Internal Types

R.V.COLLEGE OF ENGINEERING Page 179

Page 180: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

We know that any member of a class can be declared for its level of visibility

(access specifier) using the keyword public, private, protected, internal and

protected internal. Just like members, the type (class, structure, interface, delegate,

enumeration) itself can be specified for its level of visibility.

The method/member visibility is used to know which members can be accessed

from an object of the type, where as, the type visibility is used to know which

parts of the system can create the object of that type.

A non-nested C# type can be marked by either public or internal and nested types

can be specified with any of public, private and internal. The public types can be

created by any other objects within the same assembly or by other external

assemblies. But, the internal types can be created by the types within the same

assembly and are not accessible outside the assembly. By default, the visibility

level of a class is internal. For example,

//this class can be used outside this assembly also

public class Test

{

//body of the class

}

//this class can be accessed only within its assembly

internal class Test

{

//body of the class

}

R.V.COLLEGE OF ENGINEERING Page 180

Page 181: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Or

class Test //by default, it is internal

{

//body of the class

}

3.18Recapping the Pillars of OOP

All the object oriented languages possess three principals (considered to be pillars

of OOP) viz.

Encapsulation : How the languages hide an object’s internal

implementation?

Inheritance : How the languages promote code reuse?

Polymorphism : How the languages let the programmer to treat

related objects in a similar way?

Here, we will discuss the basic role of each of these pillars and then move forward

for detailed study.

Encapsulation Services

Encapsulation is the ability to hide unnecessary implementation details from the

object user. For example, assume we have created a class named DBReader having

methods open() and close():

R.V.COLLEGE OF ENGINEERING Page 181

Page 182: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

DBReader d=new DBReader();

d.open(“C:\MyDatabase.mdf”);

……..

d.close();

The class DBReader has encapsulated the inner details of locating, loading,

manipulating and closing data file. But, the object user need not worry about all

these.

Closely related to the notion of encapsulation is data hiding. We do this by making

data members as private. The private data can be modified only through the public

member functions of that class.

Inheritance: The is-a and has-a Relationships

Inheritance is the ability to create new class definitions based on existing class

definitions. In other words, inheritance allows us to extend the behavior of base

class by inheriting core functionality into a derived class.

For example, we know that System.Object is the topmost class in .NET. We can

create a class called Shape which defines some properties, fields, methods and

events that are common to all the shapes. The Hexagon class extends Shape and

inherits properties of Shape and Object. It contains properties of its own. Now, we

can say Hexagon is a Shape, which is an object. Such kind of relationship is called

as is-a relationship and such inheritance is termed as Classical inheritance.

R.V.COLLEGE OF ENGINEERING Page 182

Page 183: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

There is another type of code reuse in OOP viz. the containment/delegation

model or has-a relationship. This type of reuse is not used for base class/child

class relationships. Rather, a given class can define a member variable of other

class and make use of that either fully or partly.

For example, a Car can contain Radio. The containing type (Car) is responsible for

creating the inner object (Radio). If the Car wishes to make the Radio’s behavior

accessible from a Car instance, it must provide some set of public functions that

operate on the inner type.

Polymorphism: Classical and Ad Hoc

Polymorphism can be of two types viz. classical and Ad Hoc. A Classical

polymorphism takes place in the languages that support classical inheritance.

The base class can define a set of members that can be overridden by a subclass.

R.V.COLLEGE OF ENGINEERING Page 183

Object

Shape

Hexagon

Car

Radio

//Method of Car

void TurnOnRadio(bool on)

{

//Delegate to inner Radio

radioObj.Power(on);

}

Page 184: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

When subclass overrides the behavior defined by a base class, they are essentially

redefining how they respond to the same message. For example, assume Shape

class has defined a function named Draw() without any parameter and returning

nothing. As every shape has to be drawn in its own manner, each subclass like

Hexagon, Circle etc. can redefine the method Shape() as shown –

Classical polymorphism allows a base class to enforce a given behavior on all

subclasses.

Ad hoc polymorphism allows objects that are not related by classical inheritance

to be treated in a similar manner, provided that every object has a method of the

exact signature. Languages that support ad hoc polymorphism possess a technique

called late binding to find the underlying type of given object at runtime.

Consider the following situation:

R.V.COLLEGE OF ENGINEERING Page 184

Object

Shape

Hexagon

void Draw()

Circle

Draw()

Draw()

Page 185: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Note that the three classes Circle, Hexagon and Rectangle are not from same base.

Still each class supports an identical Draw() method. This is possible by

implementing Draw() method on generic types. When a particular type is used for

calling Draw(), it will act accordingly.

3.19The First Pillar: C#’s Encapsulation Services

The concept of encapsulation says that the object’s data should not be directly

accessible from a method. If the data is to be manipulated, it has to be done

indirectly using accessor (get) and mutator(set) method. C# provides following two

techniques to manipulate private data members –

Define a pair of traditional accessor and mutator methods

Defined a named property.

It is good programming practice to make all the data members or fields of a class as

private. This kind of programming is known as black box programming.

Enforcing Encapsulation Using Traditional Accessors and Mutators

R.V.COLLEGE OF ENGINEERING Page 185

Circle Hexagon Rectangle

Draw() Draw() Draw()

Page 186: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

If we want to access any private data, we can write a traditional accessor (get

method) and when we want to provide value to data, we can write a mutator (set

method). For example,

class Emp

{

string Name;

public string GetName() //accessor

{

return Name;

}

public void SetName(string n) //mutator

{

Name=n;

}

}

class Test

{

public static void Main()

{

Emp p=new Emp();

p.SetName(“Ramu”);

R.V.COLLEGE OF ENGINEERING Page 186

Page 187: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Console.WriteLine(“{0}”,p.GetName());

}

}

In this example, using the public methods, we could able access private data.

Another Form of Encapsulation: Class Properties

Apart from traditional accessors and mutators, we can make use of properties

provided by .NET class (and structures, interfaces). Properties resolve to a pair of

hidden internal methods. The user need not call two separate methods to get and

set the data. Instead, user is able to call what appears to be a single named field.

For illustration, consider the following example –

using System;

class Emp

{

string Name;

public string EmpName // EmpName is name of property

{

get

{

return Name; // Name is field-name

}

set

{

Name=value; // value is a keyword

R.V.COLLEGE OF ENGINEERING Page 187

Page 188: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

}

}

}

class Test

{

public static void Main()

{

Emp p=new Emp();

p.EmpName="Ramu"; //use name of the property

Console.WriteLine("{0}",p.EmpName);

}

}

A C# property is composed using a get block (accessor) and set block (mutator).

The value keyword represents the right-hand side of the assignment. Though, value

is an object, the underlying type of the object depends on which kind of data it

represents. For example, in the previous program, the property EmpName is

operating on a private string, which maps to System.String. Unlike traditional

accessors and mutators, the properties make our types easier to manipulate.

Properties are able to respond to the intrinsic operators in C#. For example,

using System;

class Emp

{

R.V.COLLEGE OF ENGINEERING Page 188

Page 189: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

int Sal;

public int Salary

{

get

{

return Sal;

}

set

{

Sal=value;

}

}

}

class Test

{

public static void Main()

{

Emp p=new Emp();

p.Salary=12000;

p.Salary++;

Console.WriteLine("{0}",p.Salary); //12001

p.Salary -=400;

Console.WriteLine("{0}",p.Salary); //11601

}

R.V.COLLEGE OF ENGINEERING Page 189

Page 190: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

}

Read-only and Write-only Properties

In some of the situations, we just want to set a value to a data member and don’t

want to return it. In such a situation, we can omit get block. A property with only a

set block is known as write-only property. In the same manner, we can just have a

get block and omit set block. A property with only a get block is known as read-

only property. For example,

class Emp

{

string SSN, name;

int EmpID;

public Emp(string n, int id)

{

name=n;

EmpID=id;

}

public string EmpSSN //read-only property

{

get{ return SSN;}

}

}

Understanding static properties

R.V.COLLEGE OF ENGINEERING Page 190

Page 191: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

C# supports static properties. Note that, static members of a class are bound to

class but not for objects. That is, to access static members, we need not create an

object of the class. The same rule will apply to static properties too. For example,

class Emp

{

static string CompanyName;

public static string Company

{

get{ return CompanyName; }

set{ CompanyName=value; }

}

public static void Main()

{

Emp.Company=“RNSIT”; //use class name

Console.WriteLine(“We are at {0}”, Emp.Company);

}

}

Understanding static Constructors

As we have seen, static properties can be used to set and get values for static

members. Assume a situation, where we need to just set a value commonly for all

the objects. Writing a static write-only property with a set-block and then assigning

value is quite time-consuming. For this purpose, C# provides another method for

doing so, through static constructors. For example,

R.V.COLLEGE OF ENGINEERING Page 191

Page 192: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

class Emp

{

static string CompanyName;

static Emp()

{

CompanyName=“RNSIT”;

}

public static void Main()

{

Console.WriteLine(“We are at {0}”, Emp.Company);

}

}

Now, all the objects of Emp class will be set the value ”RNSIT” for the member

CompanyName automatically as soon as the objects gets created.

3.20Pseudo-Encapsulation: Creating Read-Only Fields

Just like read-only properties, we have a notion of read-only fields. Read-only fields

offer data preservation via the keyword readonly. The readonly field can be given a

value through assignment only at the time of declaration or as a part of constructor.

class Student

{

public readonly int Sem=5; //assignment during declaration

R.V.COLLEGE OF ENGINEERING Page 192

Page 193: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

public readonly string USN;

string name;

public Student(string n, string usn)

{

name=n;

USN=usn; //assignment through constructor

}

public static void Main()

{

Student s1=new Student(“Abhishek”, “1RN07MCA01”);

s1.Sem= 3; //error

s1.USN=“1RN07MCA02”; //error

………

}

}

NOTE:

• The keyword readonly is different from const.

• The const fields can be assigned a value at the time of declaration only and

assignment is not possible there-after.

• So, const fields will have same value through out the program, as it is

compile-time constant.

• On the other hand, readonly fields can be assigned a value through

constructor also.

• So, they can have different values based on constructor call.

R.V.COLLEGE OF ENGINEERING Page 193

Page 194: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

• For example –

class Student

{

public readonly int Sem=5; //make Sem as 5 for all objects

public readonly string USN;

string name;

public Student(string n, string usn)

{

name=n;

USN=usn;

}

public Student(string n, string u, int s) //change sem for one student

{

name=n;

USN=u;

Sem=s;

}

public static void Main()

{

Student s1=new Student(“Ramu”, “MCA01”); //sem is 5 by default

Student s2=new Student(“Shyam”, “CS02”, 3); //sem is set to 3

--------------

R.V.COLLEGE OF ENGINEERING Page 194

Page 195: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

}

}

In the above example, if the field Sem would have been specified with const

modifier, then trying to change the value through constructor will generate error.

But, readonly keyword will allow the programmer to keep some fields as constant

unless and otherwise specified through constructor.

3.21Summary

Encapsulation is one of the basic building blocks of object oriented programming

language. In C#, we can achieve encapsulation either by writing accessor and

mutator methods or by writing properties. Again, based on our need in a program,

we can write read-only/write-only properties. One can make use of static

constructors and read-only fields too.

3.22Keywords

Method Overloading

The keyword this and Forwarding constructor calls

Method/Member visibility and Type visibility

Encapsulation, Inheritance, Polymorphism, Data hiding

Is-a and Has-a relationship (Classical inheritance and Containment/Delegation

model)

Classical and Ad-hoc Polymorphism

Late Binding

Accessor and Mutators

Properties (get and set): Read-only, Write-only, static

Static Constructors and Read-only fields

R.V.COLLEGE OF ENGINEERING Page 195

Page 196: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

3.23 Exercises

1. What are the basic components of Object oriented programming and how they

are implemented? Give examples.

2. How do you overload a method? Explain with an example.

3. What do you mean by forwarding constructor calls? Explain.

4. What are member visibility and type visibility?

5. Explain “is-a” and “has-a” relationship with respect to inheritance.

6. What is encapsulation? What are two ways of enforcing encapsulation? Give

examples for both the methods.

7. Explain the concept of static properties with example.

8. What do you mean by static constructors? Write a program to illustrate the

same.

9. Explain the concept of readonly fields with an example.

Module 2

Unit 4

CONTENTS:

1.29 Objectives4.2 Introduction

4.3The Second Pillar: C#’s Inheritance Supports

4.4Keeping family secrets: The “Protected” Keyword

4.5Nested Type Definitions

4.6The Third Pillar: C#’s Polymorphic Support

4.7Casting Between

4.8Summary

R.V.COLLEGE OF ENGINEERING Page 196

Page 197: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

4.9 Keywords

4.10 Exercises

5.1 Objectives

At the end of this lesson, the students will understand:

The concept of Inheritance

The protected members of a class

Sealed classes

Polymorphism

Virtual Methods

Abstract Classes

Abstract Methods

Versioning Class Members

Implicit and Explicit Casting

4.16Introduction

The previous unit elaborated about one of the OOP concepts viz. Encapsulation.

Here, we will study the other two viz. Inheritance and Polymorphism. Inheritance

allows the code re-usability. The base class properties can be made use of in the

derived class. But C# does not support multiple inheritance. To get the properties of

more than one class, we need to design interfaces which will be discussed in next

module. Polymorphism means One interface, multiple forms. Under this, we are

going to study the concept of abstract classes, abstract methods, virtual methods

and so on.

R.V.COLLEGE OF ENGINEERING Page 197

Page 198: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

4.17The Second Pillar: C#’s Inheritance Supports

Inheritance facilitates code reuse. The inheritance can be either classical

inheritance (is-a relationship) or containment/delegation model (has-a

relationship).

When we establish is-a relationship between classes, we are building a dependency

between types. The basic idea of classical inheritance is that new classes may

influence and extend the functionality of other classes. The hierarchy may look

something like –

Now we can say that, Manager is-a Employee and SalesMan is-a Employee.

In classical inheritance, the base classes are used to define general characteristics

that are common to all derived classes. The derived classes extend this general

functionality while adding more specific behaviors to the class.

Consider an example –

public class Emp

R.V.COLLEGE OF ENGINEERING Page 198

Employee

Manager

SalesMan

Page 199: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

{

protected string Name;

protected int EmpID;

…………..

}

public class SalesMan:Emp //SalesMan is inherited from Emp

{

int number_of_sales; // also includes members Name, EmpID

………..

}

class Test

{

public static void Main()

{

Emp e=new Emp();

SalesMan s=new SalesMan();

------------

}

}

Controlling Base-Class Creation

Usually, the base class constructors are used to initialize the members of base

class. When derived class has few more members and if we need to initialize, then

R.V.COLLEGE OF ENGINEERING Page 199

Page 200: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

we will write constructor for derived class. In such a situation, there is a repetition of

code. For example –

public class Emp

{

protected string Name;

protected int EmpID;

public Emp(string n, int eid, float s)

{

Name=n;

EmpId=eid;

}

}

public class SalesMan:Emp

{

int number_of_sales;

public SalesMan(string n, int eid, int s)

{

Name=n; //code repeated

EmpId=eid; //code repeated

number_of_sales=s;

}

}

R.V.COLLEGE OF ENGINEERING Page 200

Page 201: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

If there is more number of data fields in the base class, then in each of the derived

class constructors, we need to repeat such assignment statements. To avoid this,

C# provides an option to explicitly call base class constructors as shown below –

public class Emp

{

protected string Name;

protected int EmpID;

public Emp(string n, int eid)

{

Name=n;

EmpId=eid;

}

}

public class SalesMan:Emp

{

int bonus;

public SalesMan(string n, int eid, int b): base(n, eid)

{

bonus=b; //other members are passed to base class to initialize

}

}

R.V.COLLEGE OF ENGINEERING Page 201

Page 202: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

class Test

{

public static void Main()

{

Emp e1=new Emp(“Ram”, 25);

SalesMan s1= new SalesMan(“Sham”, 12, 10);

------------

}

}

Multiple Base Classes

Deriving a class from more than one base class is not possible in C#. That is,

multiple inheritance is not supported by C#. When we need to use the properties of

more than one class in a derived class, we need to write interfaces rather than

classes. Then we can implement any number of interfaces to achieve code-

reusability.

4.18Keeping Family Secrets: The protected Keyword

The private members of a class can not be available to derived classes. So, we will

go for protected keeping the privacy of the data. The protected members of a

class can not be accessed from outside, but still be available to derived classes.

Preventing Inheritance: Sealed Classes

R.V.COLLEGE OF ENGINEERING Page 202

Page 203: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

In some of the situations, we may don’t want our class to be inherited by any other

class. For example –

Here, a class called Part-time SalesMan is derived from SalesMan class which in-turn

is derived from Employee class as shown in the diagram. Now, we don’t want any

more classes to be derived from Part-time SalesMan class. To prevent such

inheritance, C# provides a keyword sealed. The usage is depicted here-under:

public sealed class Part_TimeSalesMan: SalesMan

{

//body of Part_TimeSalesMan class

}

Now any attempt made to derive a class from Part_TimeSalesMan class will

generate an error:

public class Test: Part_TimeSalesMan //compile-time error!!!

{

…………..

}

R.V.COLLEGE OF ENGINEERING Page 203

Employee

SalesMan

Part-time SalesMan

Page 204: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Many of the inbuilt classes of C# are sealed classes. One such example is

System.String.

Programming for Containment/Delegation

Till now we have discussed is-a relationship. Now we will see, how to write program

for has-a relationship. Consider a class Radio –

class Radio

{

public void TurnOn(bool on)

{

if(on)

Console.WriteLine(“Radio is on”);

else

Console.WriteLine(“Radio is off”);

}

}

Now, consider a class Car –

class Car

{

int CurrSpeed, MaxSpeed;

string name;

bool carIsDead=false;

R.V.COLLEGE OF ENGINEERING Page 204

Page 205: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

public Car() { MaxSpeed=100}

public Car(string n, int m, int c)

{

name=n;

MaxSpeed=m;

CurrSpeed=c;

}

public void SpeedUp(int a)

{

if(carIsDead)

Console.WriteLine(“Out of order”);

else

{

CurrSpeed+=a;

}

}

}

Now, we have two classes viz. Radio and Car. But, we can not say, “Car is a Radio”

or “Radio is a Car”. Rather, we can say, “Car has a Radio”. Now, the Car is called

containing Class and Radio is called contained class.

To make the contained class to work, we need to re-define Car class as –

R.V.COLLEGE OF ENGINEERING Page 205

Page 206: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

class Car

{ ………..

private Radio rd=new Radio();

}

To expose the functionality of the inner class to the outside world requires

delegation. Delegation is the act of adding members to the containing class that

make use of the functionality of contained class.

class Car

{ ……….

public void Tune(bool s)

{

rd.TurnOn(s); //delegate request to inner object

}

}

To make this function work, in the Main() function we can write –

Car c=new Car();

c.Tune(false);

Thus by making one class to be a member of other class, we can establish has-a

relationship. But it is always the job of outer class to define a member function

which activates the inner class objects.

4.19Nested Type Definitions

R.V.COLLEGE OF ENGINEERING Page 206

Page 207: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

In C#, it is possible to define a type (enum, class, interface, struct, delegate)

directly within the scope of a class. When a type is nested within a class, it is

considered as a normal member of that class. For example,

class C1

{

……….. //members of outer class

class C2

{

………. //members of inner class

}

}

Nested type seems like has-a relationship, but it is not. In containment/delegation,

the object of contained class is created within containing class. But, it is possible to

create the objects wherever we wish. But in nested types, the inner class definition

is within the body of out class and hence, inner class objects can not be created

outside the outer class.

4.20The Third Pillar: C#’s Polymorphic Support

Polymorphism answers the question “how to make related objects respond

differently to the same request?” Consider the following example to illustrate the

need of polymorphism.

R.V.COLLEGE OF ENGINEERING Page 207

Page 208: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Assume we have a base class Employee and two derived classes Manager and

SalesMan.

class Employee

{

…….

public void Bonus(float b)

{

basicSal+=b;

}

}

class Manager:Employee

{

………..

}

class SalesMan: Employee

{

…………

}

Now, the classes Manager and SalesMan both contains the method Bonus(float).

Thus in the Main() function, we can call Bonus() through the objects of Manger and

SalesMan –

Manager m=new Manager();

m.Bonus(500);

R.V.COLLEGE OF ENGINEERING Page 208

Page 209: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

SalesMan s=new SalesMan()

s.Bonus(300);

Obviously, the Bonus() method works same for both the objects. But in reality, the

bonus for a SalesMan should be calculated based on number of sales. Manager can

be given bonus based on his other performance like successful completion and

delivery of a project etc. This means, we need a Bonus() method which works

differently in two derived classes.

The polymorphic technique of C# provides solution for this problem. With the help

of virtual and override keywords, we can make same function to behave

differently in base-class and all the derived classes. For example,

class Employee

{

------------------

public virtual void Bonus(float b)

{

basicSal+=b;

}

}

class SalesMan:Employee

{

------------------

public override void Bonus(float b)

R.V.COLLEGE OF ENGINEERING Page 209

Page 210: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

{

int salesBonus=0;

if(numOfSales<=100)

salesBonus=10;

elseif (numOfSales<=200)

salesBonus=20;

base.Bonus(b*salesBonus); //use of base class method

}

}

class Test

{

public static void Main()

{

Employee e=new Employee();

e.Bonus(100); //base class Bonus() is called

SalesMan s=new SalesMan()

s.Bonus(300); //derived class Bonus() is called

}

}

We can see that when the Bonus() method is invoked through base class object, the

corresponding method will be called. Whereas, when Bonus() is invoked with the

object s of derived class, the overridden method Bonus() will be called.

R.V.COLLEGE OF ENGINEERING Page 210

Page 211: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

NOTE that any overridden method is free to call its corresponding base class

method using the keyword base. Thus, the overridden method can have its own

statements and also can make use of the behaviors of base class virtual method

also.

Defining Abstract Classes

Sometimes, the creation of base class objects will not be of any use. For example,

an Employee is always identified with a designation. Thus, an employee must be

either a Manager or a SalesMan or working at some such other designation. So,

creation of the object of class Employee is useless. In such situations, we can

prevent base class instantiation by making it as abstract.

public abstract class Employee

{

………

}

Employee e=new Employee //error !!

Thus, abstract class is a class which just declares members (data and method) and

no object can be created for this class. The member methods of abstract class may

be used by the objects of derived class either directly or by overriding them in the

derived class.

Enforcing Polymorphic Activity: Abstract Methods

An abstract class may contain the definition for methods it is defining. The derived

classes are free to use such methods directly or they can override and then use. But

R.V.COLLEGE OF ENGINEERING Page 211

Page 212: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

in some situations, the definitions of abstract base-class methods may not be

useful. The derived classes only should define the required behavior. In this case,

we need to force the derived classes to override the base class methods. This is

achieved using abstract methods.

An abstract class can define any number of abstract methods, which will not supply

any default implementation. Abstract method is equivalent to pure virtual

functions of C++. The abstract methods can be used whenever we wish to define

a method that does not supply a default implementation. To understand the need

for abstract methods, consider the following situation:

Here, each derived class like Hexagon and Circle of Shape has to override Draw()

method to indicate the methodology of drawing itself. If any derived class forgets to

override Draw() method, the code may look like –

abstract class Shape

{

public virtual void Draw()

{

R.V.COLLEGE OF ENGINEERING Page 212

Object

Shape

Hexagon

Circle

virtual void Draw()

Draw()

Draw()

Page 213: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Console.WriteLine(“Shape.Draw()”);

}

}

public class Circle:Shape()

{

public Circle();

--------------

}

public class Hexagon:Shape()

{

…………..

public override void Draw()

{

Console.WriteLine(“Hexagon.Draw()”);

}

}

public class Test

{

public static void Main()

{

Circle c= new Circle();

c.Draw(); //Draw() method of Shape class is called

R.V.COLLEGE OF ENGINEERING Page 213

Page 214: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Hexagon h=new Hexagon();

h.Draw(); //Draw() method of Hexagon class is called

}

}

In this example, the Circle class is not overriding the Draw() method. So, when the

Draw() method is invoked through the object of Circle class, the Draw() method of

Shape class itself will be called. Obviously, the Draw() method of Shape class will

not be having any information about how to draw a circle and hence it will be

meaningless. This shows that virtual methods of base class need not be

overridden by derived classes.

When programmer must be forced to override Draw() method, the method of base

class must be made abstract –

abstract class Shape

{

// completely abstract method. Note the semicolon at the end

public abstract void Draw();

----------

}

public class Circle:Shape()

{ -----------------

public override void Draw() //has to override

{

R.V.COLLEGE OF ENGINEERING Page 214

Page 215: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Console.WriteLine(“Circle.Draw()”);

}

}

public class Hexagon:Shape()

{ …………..

public override void Draw() //has to override

{

Console.WriteLine(“Hexagon.Draw()”);

}

}

public class Test

{

public static void Main()

{

Circle c= new Circle();

c.Draw(); //Draw() method of Circle class is called

Hexagon h=new Hexagon();

h.Draw(); //Draw() method of Hexagon class is called

}

}

Thus, by making a base class method as abstract, we are making use of run-time

polymorphism or late binding. That is, the binding between the object and the

R.V.COLLEGE OF ENGINEERING Page 215

Page 216: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

method to be invoked is decided only at runtime. This concept is more clear when

we re-design our Main() function in the following format:

public static void Main()

{

Shape[ ] s={new Circle(), new Hexagon()};

for(int i=0;i<s.Length;i++)

s[i].Draw();

}

This may seems to be quite interesting. Till now, we have heard that we can not

create objects for abstract classes. But in the above code snippet, we are creating

array of objects of base-classes. How? This is very obvious as array of objects stores

references to variables but not the objects directly. Thus, in the above example,

s[0] stores reference to the object of type Circle and s[1] stores reference to the

object of type Hexagon.

In the for loop, when we use the statement –

s[i].Draw();

the content (i.e. whether reference to Circle or reference to Hexagon) of

s[i] is considered to decide which Draw() method to be invoked and the

type (i.e. here type is Shape) of s[i] is ignored. This is nothing but run-

time polymorphism or late binding.

NOTE (Very important):

R.V.COLLEGE OF ENGINEERING Page 216

Page 217: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

After dealing with entire story about abstract classes and abstract methods,

somebody may feel what exactly is the difference between abstract classes and

interfaces? Because just-like abstract classes, interfaces also provide just a

prototype of the methods and the implementing classes have to define those

methods. (more about interfaces in Module 3)

The major difference comes in case of multiple inheritance. We know that we can

not derive a class from more than one base-class in C#. That is multiple inheritance

is not possible. But, we may have a situation where there is more than one base

class and we need to derive a class from all those base classes and then override

the virtual methods present in all the base classes. In such a situation, instead of

writing abstract base classes, we should write interfaces. Because, a class can be

derived from one base class and it can implement many number of interfaces.

Versioning class members

C# provides facility of method hiding, which is logical opposite of method

overriding. Assume the following situation:

R.V.COLLEGE OF ENGINEERING Page 217

Object

Shape

Hexagon

Circle

Oval

Abstract Draw() method defined

Draw() method implemented

Completely new Draw() method

hiding Circle.Draw()

Page 218: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

The class Circle is derived from Shape. The Shape class has an abstract method

Draw() which is overridden within Circle class to indicate how to draw a circle. The

class Oval behaves similar to Circle. But, methodology for drawing an oval is

different from that of circle. So, we need to prevent the Oval class from

inheriting Draw() method. This technique is known as versioning a class. This is

achieved by using the key word new as shown below –

public class Oval: Circle

{

public Oval()

{

------

}

public new void Draw()

{

//Oval specific drawing algorithm

}

}

Now, when we create an object of Oval class and invoke Draw() method, the most

recently used definition of Draw() is called. That is,

Oval ob=new Oval();

ob.Draw(); //calls the Draw() method of Oval class

R.V.COLLEGE OF ENGINEERING Page 218

Page 219: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Thus, the keyword new breaks the relationship between the abstract Draw() method

defined by the base class and the Draw() method in the derived class.

On the other hand, if we wish, we can make use of the base class method itself by

using explicit casting:

Oval obj=new Oval();

((Circle)obj).Draw(); //calls Draw() method of Circle class

NOTE:

The method hiding is useful when we are making use of the types defined in

another .NET assembly and we are not sure whether that type contains any method

with the same name as we are using. That is, in our application we may be using

inbuilt classes (with the help of keyword using). We are going to create a method

Draw() in our application, but we are not sure whether any of the inbuilt class

contains a method with same name. In such a situation, we can just put a keyword

new while declaring our method. This will prevent the possible call to built-in class

method.

4.21Casting Between

Till now, we have discussed number of class hierarchies. Now we should know the

laws of casting between class types. Consider the following situation, where we

have is-a relationship –

R.V.COLLEGE OF ENGINEERING Page 219

Page 220: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Keeping the above class hierarchy in mind, the following declarations are purely

valid.

object ob=new Manager();

Employee e=new Manager();

SalesMan s= new Part_timeSalesMan();

In all these situations, the implicit casting from derived class to base class is done

by the C# CLR. On the other hand, when we need to convert base class reference to

be stored in derived class object, we should make explicit casting as –

object ob;

Manager m=(Manager)ob;

Here, the explicit cast from base class to derived class is done.

Determining the Type-of Objects

R.V.COLLEGE OF ENGINEERING Page 220

Object

Employee

Manager

SalesMan

Part_time

SalesMan

Page 221: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

C# provides three ways to determine if a base class reference is actually referring

to derived types:

• Explicit casting

• is keyword

• as keyword

We have seen explicit casting just now. The usage of other two methodology is

depicted with the help of examples:

Object ob=new Manager();

if(ob is Manager) //checking whether ob is Manager

//do something

Employee e;

SalesMan s= e as SalesMan; //converting Employee type to SalesMan type

//do something with s

Numerical Casts

In addition to casting between objects, the numerical conversions also follow similar

rules. When we are trying to cast larger (in size of type) type to smaller type, we

need to make explicit casting:

int x=25000;

byte b=(byte)x; //loss of information

While converting from larger type to smaller type, there is a chance of data-loss.

R.V.COLLEGE OF ENGINEERING Page 221

Page 222: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

When we need to cast smaller type to larger type, the implicit casting is done

automatically:

byte b=23;

int x=b; //implicit casting

There will not be any loss of data during such casting.

4.22Summary

Till now, we have discussed some of very important features of C# programming

language. While developing huge project or a product, the concepts inheritance and

polymorphism makes sense. The developer should understand when and where to

use the concept of abstract classes virtual functions etc.

4.23Keywords

Classical Inheritance (is-a relationship)

Containment/ Delegation Model (has-a relationship)

The keywords protected and sealed

The keywords abstract, virtual, base and override

Abstract methods or Pure Virtual functions

Run-time Polymorphism or Late Binding

Implicit and Explicit type casting

The keywords is and as

4.24 Exercises

R.V.COLLEGE OF ENGINEERING Page 222

Page 223: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

5. How do you explicitly call base class constructor from derived class

constructor? Explain with an example.

6. What do you mean by nested classes? What is the difference between nested

classes and Containment/delegation?

7. How do you prevent inheritance using sealed classes? Explain with an

example.

8. With an example, explain the concept of abstract classes.

9. Write a program to demonstrate the concept of virtual and override

keywords.

10.Explain the concept of late binding with an example.

11.Write a note on Casting.

12.Explain abstract methods with example.

13.What do you mean by versioning members? Explain.

Module 3

Unit 1

CONTENTS:

1.30 Objectives1.31 Introduction1.32 Meaning of Errors and Exceptions1.33 The Role of .NET Exception Handling1.34 The System. Exception Base Class1.35 Throwing a Generic Exception1.36 Catching Exception1.37 CLR System – Level Exception (System.SystemException)1.38 Custom Application-Level Exception (System.ApplicationException)

1.39 Handling Multiple Exceptions 1.40 The Finally Block 1.41 Dynamically Identifying Application and System Level

R.V.COLLEGE OF ENGINEERING Page 223

Page 224: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Exceptions

1.42 Summary1.43 Keywords1.44 Exercises

1.25 Objectives

At the end of this lesson, the students will understand:

The meaning of exceptions

Types of exceptions: System and Application

Usage of keywords like try, catch, throw, finally

Building user-defined/custom exceptions

1.26 Introduction

The point of this unit is to understand how to handle runtime anomalies in your

code base through the use of structured exception handling. Not only will you learn

about the C# keywords that allow you to handle such problems, but you will also

come to understand the distinction between application-level and system-level

exceptions. This discussion will also provide a lead-in to the topic of building custom

exceptions types as well as how to leverage the built-in exception handling

functionality of VS.NET.

1.27 Meaning of Errors, Bugs and Exceptions

Mistakes are bound to happen during programming. Problems may occur due to

bad code like overflow of array index, invalid input etc. So, the programmer needs

R.V.COLLEGE OF ENGINEERING Page 224

Page 225: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

to handle all possible types of problems. There are three terminologies to define

mistakes that may occur.

• Bugs:

– Errors done by the programmer.

– Example: making use of NULL pointer, referring array index out of

bound, not deleting allocated memory etc.

• Errors:

– Caused by user of the application.

– For example: entering un-expected value in a textbox, say USN.

• Exceptions:

– Runtime anomalies those are difficult to prevent.

– Example: trying to open a corrupted file, trying to connect non-existing

database etc.

1.28 The Role of .NET Exception Handling

The .NET platform provides a standard technique to send and trap runtime errors:

structured exception handling (SEH). The beauty of this approach is that developers

now have a unified approach to error handling, which is common to all languages

targeting the .NET universe. Another bonus of .NET exceptions is the fact that rather

than receiving a cryptic numerical value that identifies the problem at hand,

exceptions are objects that contain a human-readable description of the problem,

as well as a detailed snapshot of the call stack that triggered the exception in the

first place. Furthermore, you are able to provide the end user with help link

information that points the user to a URL that provides detailed information

regarding the error at hand as well as custom user-defined data.

The Atoms of .NET Exception Handling

R.V.COLLEGE OF ENGINEERING Page 225

Page 226: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Programming with structured exception handling involves the use of four

interrelated entities:

A class type that represents the details of the exception that occurred

A member that throws an instance of the exception class to the caller

A block of code on the caller’s side that invokes the exception-prone member

A block of code on the caller’s side that will process (or catch) the exception

should it occur

The C# programming language offers four keywords (try, catch, throw, and finally)

that allow you to throw and handle exceptions. The type that represents the

problem at hand is a class derived from System.Exception

1.29 The System.Exception Base Class

All user- and system-defined exceptions ultimately derive from the

System.Exception base class (which in turn derives from System.Object). Core

Members of the System.Exception Type are shown below:

System.Exception

Property

Meaning

HelpLink This property returns a URL to a help file describing the error in full detail.

InnerException Used to obtain information about the previous exceptions that caused the current exception to occur. The previous exceptions are recorded by passing them into the constructor of the most current exception. This is a read-only property.

Message Returns the textual description of a given error. The

R.V.COLLEGE OF ENGINEERING Page 226

Page 227: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

error message itself is set as a constructor parameter. This is a read-only property.

Source Returns the name of the assembly that threw the exception.

StackTrace Contains a string that identifies the sequence of calls that triggered the exception. This is a read-only property.

TargetSite Returns a Method-Base type, which describes numerous details about the method that threw the exception (ToString() will identify the method by name). This is a read-only property.

1.30 Throwing a Generic Exception

During the program, if any exception occurs, we can throw it to either a specific

exception like FileNotFoundException, ArrayIndexOutOfBoundException,

DivideByZeroException etc. or we can through a generic exception directly using

Exception class. The object of Exception class can handle any type of exception, as

it is a base class for all type of exceptions. Here is an example to show how to

throw an exception:

using System;

class Test

{

int Max=100;

public void Fun(int d)

{

if(d>Max)

R.V.COLLEGE OF ENGINEERING Page 227

Page 228: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

throw new Exception("crossed limit!!!");

else

Console.WriteLine("d={0}", d);

}

public static void Main()

{

Test ob=new Test();

Console.WriteLine("Enter a number:");

int d=int.Parse(Console.ReadLine());

ob.Fun(d);

}

}

Output:

Enter a number: 12

d=12

Enter a number: 567

Unhandled Exception: System.Exception: crossed limit!!!

at Test.Fun(Int32 d)

at Test.Main()

In the above example, if the entered value d is greater than 100, then we are

throwing an exception. We are passing message “crossed limit” to a Message

property of Exception class.

R.V.COLLEGE OF ENGINEERING Page 228

Page 229: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Deciding exactly what constitutes throwing an exception and when to throw an

exception is up to the programmer.

1.31 Catching Exceptions

When a block of code is bound to throw an exception, it needs to be caught using

catch statement. Once we catch an exception, we can invoke the members of

System.Exception class. Using these members in the catch block, we may display a

message about the exception, store the information about the error in a file, send a

mail to administrator etc. For example,

using System;

class Test

{

int Max=100;

public void Fun(int d)

{

try

{

if(d>Max)

throw new Exception("crossed limit!!!");

}

catch(Exception e)

{

Console.WriteLine("{0}", e.Message);

R.V.COLLEGE OF ENGINEERING Page 229

Page 230: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

}

Console.WriteLine("d={0}", d);

}

public static void Main()

{

Test ob=new Test();

Console.WriteLine("Enter a number:");

int d=int.Parse(Console.ReadLine());

ob.Fun(d);

}

}

Output:

Enter a number: 12

d=12

Enter a number: 123

crossed limit!!!

d=123

In the above example, we are throwing an exception if d>100 and is caught.

Throwing an exception using the statement –

throw new Exception (“Crossed Limit”);

means, creating an object of Exception class and passing that object to catch block.

While passing an object, we are passing the message also, which will be an input for

the Message property of Exception class.

R.V.COLLEGE OF ENGINEERING Page 230

Page 231: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

A try block is a section of code used to check for any exception that may be

encountered during its scope. If an exception is detected, the program control is

sent to the appropriate catch block. If the code within try block does not trigger any

exception, then the catch block is skipped fully and program will continue to

execute further.

Once an exception has been handled, the application will continue its execution

from very next point after catch block. In some situations, a given exception may be

critical and it may warrant the termination of the application. However, in most of

the cases, the logic within the exception handler will ensure the application to be

continued in very normal way.

The TargetSite Property

The System.Exception.TargetSite property allows to determine various details

about the method that threw a given exception.

Printing the value of TargetSite will display the return type, name, and

parameters of the method that threw the exception.

However, TargetSite does not simply return a string, but a strongly typed

System.Reflection.MethodBase object.

This type can be used to gather numerous details regarding the offending

method as well as the class that defines the offending method.

The StackTrace Property

• The System.Exception.StackTrace property allows you to identify the series of

calls that resulted in the exception.

• Be aware that you never set the value of StackTrace as it is established

automatically at the time the exception is created.

• The string returned from StackTrace documents the sequence of calls that

resulted in the throwing of this exception.

R.V.COLLEGE OF ENGINEERING Page 231

Page 232: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

using System;

class Test

{

int Max=100;

public void Fun(int d)

{

try

{

if(d>Max)

throw new Exception(string.Format("crossed limit!!!"));

}

catch(Exception e)

{

Console.WriteLine("{0}",e.Message); // crossed limit!!!

Console.WriteLine("{0}", e.TargetSite); //Void Fun(Int32)

Console.WriteLine("{0}",e.TargetSite.DeclaringType); //Test

Console.WriteLine("{0}", e.TargetSite.MemberType); //Method

Console.WriteLine("Stack:{0}", e.StackTrace);

//at Test.Fun(Int32 d)

}

Console.WriteLine("d={0}", d);

}

public static void Main()

{

R.V.COLLEGE OF ENGINEERING Page 232

Page 233: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Test ob=new Test();

Console.WriteLine("Enter a number:");

int d=int.Parse(Console.ReadLine()); //assume d is 123

ob.Fun(d);

}

}

NOTE: The comment lines for the statements within the function Fun() are the

outputs for the input d greater than 100.

The Helplink Property

• The HelpLink property can be set to point the user to a specific URL or

standard Windows help file that contains more detailed information.

• By default, the value managed by the HelpLink property is an empty string.

• If you wish to fill this property with an interesting value, you will need to do

so before throwing the System.Exception type.

using System;

class Test

{

int Max=100;

public void Fun(int d)

{

try

{

if(d>Max)

R.V.COLLEGE OF ENGINEERING Page 233

Page 234: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

{

Exception ex= new Exception("crossed limit!!!");

ex.HelpLink="g:\\Help.doc";

throw ex;

}

}

catch(Exception e)

{

Console.WriteLine("{0}", e.HelpLink); // G:\Help.doc

}

Console.WriteLine("d={0}", d);

}

public static void Main()

{

Test ob=new Test();

Console.WriteLine("Enter a number:");

int d=int.Parse(Console.ReadLine()); //say d=345

ob.Fun(d);

}

}

1.32 CLR System Level Exceptions

R.V.COLLEGE OF ENGINEERING Page 234

Page 235: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

The .NET base class libraries define many classes derived from System.Exception.

For example, the System namespace defines core error objects such as

ArgumentOutOfRangeException, IndexOutOfRange-Exception,

StackOverflowException etc. Other namespaces define exceptions that reflect the

behavior of that namespace. For ex. System.Drawing.Printing defines printing

exceptions, System.IO defines IO-based exceptions, System.Data defines database-

centric exceptions, and so on.

Exceptions that are thrown by the methods in the BCL are called system exceptions.

These exceptions are regarded as non-recoverable, fatal errors. System exceptions

derive directly from a base class named System.SystemException, which in turn

derives from System.Exception (which derives from System.Object):

public class SystemException : Exception

{

// Various constructors.

}

The System.SystemException type does not add any additional functionality beyond

a set of constructors.

1.33 Custom Application Level Exceptions

All .NET exceptions are class types and hence we can create our own application-

specific exceptions. Since the System.SystemException base class represents

exceptions thrown from the CLR, we may naturally assume that we should derive

R.V.COLLEGE OF ENGINEERING Page 235

Page 236: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

your custom exceptions from the System.Exception type. But, the best practice is

to derive from the System.ApplicationException type:

public class ApplicationException : Exception

{

// Various constructors.

}

The purpose of System.ApplicationException is to identify the source of the

(nonfatal) error. When we handle an exception deriving from

System.ApplicationException, we can assume that exception was raised by the

code-base of the executing application rather than by the .NET BCL. The

relationship between exception-centric base classes are shown –

R.V.COLLEGE OF ENGINEERING Page 236

System.ApplicationException

System.Object

System.Exception

Your Application’s

Custom Exceptions

System.SystemException

Exceptions from

.NET BCL

Page 237: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Truly speaking, it is not necessary to derive a custom exception from

System.ApplicationException class, rather it can directly be derived from more

generic System.Exception class. To understand various possibilities, now we will

build custom exceptions.

Building Custom Exceptions: Take One

We can always throw instances of System.Exception to indicate runtime error. But,

it is better to build a strongly typed exception that represents the unique details of

our current problem. The first approach is defining a new class derived directly

from System.Exception. Like any class, the exception class also may include fields,

methods and properties that can be used within the catch block. We can also

override any virtual member in the parent class. For example, assume we wish to

build a custom exception (named CarIsDeadException) to represent that the car has

crossed the maximum speed limit.

public class CarIsDeadException : System.Exception

{

private string messageDetails;

public CarIsDeadException(){ }

public CarIsDeadException(string message)

{

messageDetails = message;

}

// Override the Exception.Message property.

public override string Message

R.V.COLLEGE OF ENGINEERING Page 237

Page 238: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

{

get

{

return string.Format("Car Error Message: {0}", messageDetails);

}

}

}

public class Car

{

……………………

public void SpeedUp(int delta)

{

try

{

speed=current_speed + delta;

if(speed>max_speed)

throw new CarIsDeadException(“Ford Ikon”);

}

catch(CarIsDeadException e)

{

Console.WriteLine(“Method:{0}”, e.TargetSite);

Console.WriteLine(“Message:{0}”, e. Message);

}

}

……………………..

R.V.COLLEGE OF ENGINEERING Page 238

Page 239: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

}

Note that, the custom exceptions are needed only when the error is tightly bound to

the user-defined class issuing the error. For example, a File class may throw number

of file-related errors; Student class may throw errors related to student information

and so on. By writing the custom exception, we provide the facility of handling

numerous exceptions on a name-by-name basis.

Building Custom Exceptions: Take Two

We can write the constructors, methods and overridden properties as we wish in our

exception class. But it is always recommended approach to build a relatively simple

type that supplied three named constructors matching the following signature –

public class CarIsDeadException : System.Exception

{

public CarIsDeadException(){ }

public CarIsDeadException(string message):base(message)

{

}

public CarIsDeadException(string message, Exception

innerEx):base(message, innerEx)

{

}

}

R.V.COLLEGE OF ENGINEERING Page 239

Page 240: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Most of the user defined exceptions follow this pattern. Because, many times, the

role of a custom exception is not to provide additional functionality beyond what is

provided by its base class. Rather, to provide a strongly named type that clearly

identifies the nature of the error.

Building Custom Exceptions: Take Three

We have discussed that; exceptions can be system-level or application-level. If we

want to clearly mark our exception to be thrown by the application itself and not by

any chance by BCL, we can redefine as –

public class CarIsDeadException: ApplicationException

{

//body

}

1.34 Handling Multiple Exceptions

We have seen a situation where a try block will have corresponding catch block. But

in reality, we may face a situation where the code within try block may trigger

multiple possible exceptions. For example,

public void SpeedUp(int delta)

{

try

{

if(delta<0)

R.V.COLLEGE OF ENGINEERING Page 240

Page 241: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

throw new ArgumentOutOfRangeException(“Ford Ikon”);

speed=current_speed + delta;

if(speed>max_speed)

throw new CarIsDeadException(“Ford Ikon”);

}

catch(CarIsDeadException e)

{

Console.WriteLine(“Method:{0}”, e.TargetSite);

Console.WriteLine(“Message:{0}”, e. Message);

}

catch(ArgumentOutOfRangeException e)

{

Console.WriteLine(“Method:{0}”, e.TargetSite);

Console.WriteLine(“Message:{0}”, e. Message);

}

}

In the above example, if delta is less than zero, then

ArgumentOutOfRangeException is triggered. If the speed exceeds MaxSpeed, then

CarIsDeadException is thrown. While constructing multiple catch blocks for a single

try block, we must be aware that it will be processed by the nearest available catch

block. For example, the following code snippet generates compile-time error!!

R.V.COLLEGE OF ENGINEERING Page 241

Page 242: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

try

{

----------

}

catch(Exception e)

{

--------------

}

catch(CarIsDeadException e)

{

--------------

}

catch(ArgumentOutOfRangeException e)

{

--------------

}

Here, the class Exception is a base class for all user-defined and built-in exceptions.

Hence, it can handle any type of exceptions. Thus, if Exception is the first catch-

block, the control will jump to that block itself and the other two exceptions are

unreachable. Thus, during multiple exceptions, we have to design very structured

format. The very first catch block should contain very specific exception or the most

derived type in inheritance hierarchy. Whereas the last catch block should be the

most general or the top most base class in inheritance hierarchy.

Generic Catch Statements

R.V.COLLEGE OF ENGINEERING Page 242

Page 243: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

C# supports a generic catch block that does not explicitly define the type of

exception. That is, we can write –

catch

{

Console.WriteLine(“Some error has occurred”);

}

But, using this type of catch blocks indicates that the programmer is un-aware of

the type of exception that is going to occur, which is not acceptable. Hence it is

always advised to use specific type of exceptions.

Re-throwing Exceptions

It is possible to re-throw an error to the previous caller. For example–

try

{

----------------

}

catch(CarIsDeadException e)

{

//handle CarIsDeadException partially or do something

throw e;

}

In the above code, the statement throw e will throw the exception again to

CarIsDeadException.

R.V.COLLEGE OF ENGINEERING Page 243

Page 244: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

1.35 The finally Block

The try/catch block may be added with an optional Finally block. The finally block

contains a code that always executes irrespective of any number of exceptions that

may interfere with the normal flow of execution. For example, we may want to turn-

off radio within a car before stopping the car due to any reason. Programmatically

speaking, before exiting from Main() function, we may need to turn-off radio of a

car. Then we can write –

public static void Main()

{

try

{

//increase speed

}

catch(CarIsDeadException e)

{

-----------

}

catch(ArgumentOutOfRangeException e)

{

--------------

}

finally

{

R.V.COLLEGE OF ENGINEERING Page 244

Page 245: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

CarName.TurnOffRadio();

}

}

NOTE:

The finally block is useful in following situations –

When we want to

– clean-up any allocated memory

– Close a file which is in use

– Close a database connection to a data source

The finally block will be executed even if our try block does not trigger any

exception.

This is especially helpful if a given exception requires the termination of the

current application.

1.36 Dynamically Identifying Application and System Level Exceptions

In the previous examples, we have handled each exception by its specific class

name. Alternatively, if we want to generalize our catch blocks in such a way that all

application level exceptions are handled apart from possible system-level

exceptions:

try

{

//do something

}

R.V.COLLEGE OF ENGINEERING Page 245

Page 246: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

catch(ApplicationException e)

{

---------------

}

catch(SystemException e)

{

---------------

}

Though C# has the ability to discover at runtime the underlying source of an

exception, we are gaining nothing by doing so. Because some BCL methods that

should ideally throw a type derived from System.SystemException are actually

derived from System.ApplicationException or even more generic System.Exception.

1.37 Summary

This unit examined one of the OOP-centric topic viz. exceptions. You were shown

how the .NET runtime makes use of structured exception handling to contend with

runtime problems. Using a small set of keywords (try, catch, throw and finally), C#

programmers are able to raise and handle system-level and application-level

exceptions.

1.38 Keywords

Bugs, Errors, Exceptions

System.Exception Base Class and its properties

Generic exception

R.V.COLLEGE OF ENGINEERING Page 246

Page 247: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

The keywords try, catch, throw and finally

System level and Application Level exceptions

Building Custom/User-defined exceptions

Multiple exceptions

Re-throwing Exceptions

1.39 Exercises

1. What do you understand by exception in C#? Illustrate the use of

System.Exception base class in throwing generic exceptions.

2. Differentiate between bugs, errors and exceptions. Explain the concepts of .NET

exception handling with valid example code.

3. Explain the following properties: TargetSite, StackTrace, HelpLink.

4. Explain the concept of re-throwing the exception.

5. What do you mean by custom exception? Write a program to build a custom

exception which raises an exception when the argument passed is a negative

number.

6. Briefly explain the usage of finally block.

Module 3

Unit 2

CONTENTS:

R.V.COLLEGE OF ENGINEERING Page 247

Page 248: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

1.45 Objectives2.26 Introduction2.27 Understanding Object Lifetime2.28 The CIL of new 2.29 The Basics of Garbage Collection2.30 Finalization a type2.31 The Finalization Process2.32 Building an AD Hoc Destruction Method2.33 Garbage Collection Optimizations2.34 The System. GC Type2.35 Summary2.36 Keywords2.37 Exercises

2.1 Objectives

At the end of this lesson, the students will understand the following tasks in detail:

The concept of Garbage Collection and need for it

Idea about heap memory, meaning of new during object creation

Meaning of finalization and the method Finalize()

Usage of IDisposable Interface

The System.GC class

2.25Introduction

This unit examines the process of object lifetime management as handled by the

CLR. As you will see, the .NET runtime destroys objects in a rather nondeterministic

nature. Thus, you typically do not know when a given object will be de-allocated

from the managed heap, only that it will come to pass. On this note, you will come

to understand how the System.Object.Finalize() method and IDisposable interface

can be used to interact with an object’s lifetime management. Finally, we wrap up

with an examination of the System.GC type, and illustrate a number of ways you are

able to get involved with the garbage collection process.

R.V.COLLEGE OF ENGINEERING Page 248

Page 249: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

2.26 Understanding Object Lifetime

By the example programs we have seen in previous four chapters, we can note that

we have never directly de-allocated an object from memory. That is there is no

delete keyword in C#. Rather, .NET objects are allocated onto a region of memory

termed as managed heap, where they will be automatically de-allocated by the

CLR at some time later.

Thus, the golden rule of .NET memory management is –

Allocate an object onto the managed heap using the new keyword and

forget about it.

Once an object is created using new, the CLR removes it when it is no longer

needed. That is, the CLR removes an object from the heap when it is unreachable

by the current application. For example,

public static void Main()

{

Car c=new Car(“Ford Ikon”);

………………

}

Here, c is created within the scope of Main(). Thus, once the application shuts down,

this reference is no longer valid and therefore it is a candidate for garbage

collection. But, we can not surely say that the object c is destroyed immediately

after Main() function. All we can say is when CLR performs the next garbage

collection, c is ready to be destroyed.

R.V.COLLEGE OF ENGINEERING Page 249

Page 250: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

2.27The CIL of new

Here we will discuss what actually happens when new keyword is used.

When C# encounters the new keyword, it will produce a CIL newobj instruction

to the code module.

Note that, the managed heap is not just a raw portion of memory accessed by

the CLR.

The .NET garbage collector will compact empty blocks of memory, when needed,

for the purpose of optimization.

To help this process, the managed heap maintains a pointer, referred as new

object pointer that identifies exactly where the next object will be placed on

the heap.

After these tasks, the newobj instruction informs the CLR to perform the

following sequence of events:

Calculate the total amount of memory required for the object to be

allocated. If this object contains other internal objects (i.e. has-a

relationship and/or nested type member), they are also added-up. And

the memory required for each base class is also considered (i.e is-a

relationship).

The CLR then examines the managed heap to ensure that there is enough

space for the object to be allocated. If so, the object’s constructor is called

and a reference to the object in the memory is returned.

Finally, before returning the reference, the CLR will move the new object

pointer to point to the next available slot on the managed heap.

The entire process is depicted here-under:

R.V.COLLEGE OF ENGINEERING Page 250

Page 251: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

2.28The Basics of Garbage Collection

After creating so many objects, the managed heap may become full.

When the newobj instruction is being processed, if the CLR determins that the

managed heap does not have sufficient memory to allocate the requested type,

it will perform a garbage collection in an attempt to free-up the memory.

Thus, the next rule of garbage collection is:

o If the managed heap does not have sufficient memory to allocate

a new object, a garbage collection will occur.

Now the question arise: how CLR is able to determine an object on the heap that

it is no longer needed and destroy it?

To answer this question, we should know application roots.

A root is a storage location containing a reference to an object on the heap.

In other words, a root is a variable in our application that points to some area of

memory on the managed heap.

The root can fall into any of the following categories:

– Reference to global objects (Though global objects are not allowed in

C#, raw CIL does permit allocation of global objects)

– Reference to static objects

– References to local objects within a given method

R.V.COLLEGE OF ENGINEERING Page 251

c1 c2 c3Unused Heap

SpaceCar c1=new Car(“Ford”);

Car c2=new Car(“Swift”);

Car c3=new Car(“Zen”);

New object pointer

Page 252: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

– References to object parameters passed into a method

– Any CPU register that references a local object

When a garbage collection occurs, the runtime (CLR) will check all objects on the

managed heap to determine if it is still in use (or rooted) in the application.

To do so, the CLR will build an object graph, which represents each object on

the heap that is still reachable.

The object graph documents all co-dependencies for the current object.

The CLR will ensure that all related objects are considered before a possible

garbage collection through the construction of an object graph.

The CLR will never graph the same object twice, and thus avoids the circular

reference count.

To illustrate this concept, assume that the managed heap contains a set of objects

named A, B, C, D, E, F, and G. During a garbage collection, these objects (as well as

any internal object references they may contain) are examined for active roots.

Once the graph has been constructed, unreachable objects, say, the objects C and F

are marked as garbage as shown in the following diagram:

Now, a possible object graph may look like –

R.V.COLLEGE OF ENGINEERING Page 252

A B C D E F G

Managed Heap

New Object pointer

A

GED

B

Page 253: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Here, the arrows indicate depends on or requires. For example, E depends on G, B

depends on E and also G, A is not depending on anything etc. Once an object has

been marked for collection (here, C and F), they are not considered for object graph

creation and are swept from the memory. At this point, the remaining space on the

heap is compacted, which in turn will cause the CLR to modify the set of active

application roots to refer to the correct memory location (this is done automatically

and transparently). Then, the new object pointer is readjusted to point to the next

available slot. Following diagram depicts it –

2.29Finalizing a Type

From the previous discussion, we can easily make out that the .NET garbage

collection scheme is non-deterministic in nature. In other words, we can not

determine exactly when an object will be de-allocated from the memory. This

approach seems to be quite good because, we, the programmers need not worry

once the object has been created. But, there is a possibility that the objects are

holding unmanaged resources (Win32 files etc) longer than necessary.

When we build .Net types that interact with unmanaged resources, we like to

ensure that this resource is released in-time rather than waiting for .NET garbage

collector. To facilitate this, the C# provides an option for overriding the virtual

R.V.COLLEGE OF ENGINEERING Page 253

A B D E G

Managed Heap

New Object pointer

Page 254: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

System.Object.Finalize() method. The default implementation of Finalize() method

does nothing!! Note that we need to override it only if we are making use of

unmanaged resources. Otherwise, the C# garbage collector will do the job.

C# will not allow the programmer to directly override the Finalize() method.

public class Test

{

protected override void Finalize() //error!!!

{ ………. }

}

Rather, we need to use a C++ -type destructor syntax:

public class Test

{

~Test()

{

………

}

}

Indirectly Invoking System.Object.Finalize()

We have discussed till now that the .NET runtime will trigger garbage collector when

it requires more memory that what is available at heap. But also note that, the

finalization will automatically take place when an application domain or

AppDomain is unloaded by CLR. Application domain can be assumed to be

R.V.COLLEGE OF ENGINEERING Page 254

Page 255: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Application itself. Thus, once our application is about to shut down, the finalize logic

is triggered.

Thus, the next rule of garbage collection is:

When an AppDomain is unloaded, the Finalize() method is invoked

for all finalizable objects.

For illustration, consider the following example –

using System;

class Test

{

public Test()

{ }

~Test()

{

Console.WriteLine("Finalizing!!!");

}

public static void Main()

{

Console.WriteLine(“Within Main()");

Test t=new Test();

Console.WriteLine(“Exiting Main()");

R.V.COLLEGE OF ENGINEERING Page 255

Page 256: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

}

}

Output:

Within Main()

Exiting Main()

Finalizing!!!

We can see that, once the program control goes out the scope of Main() function,

the destructor is called for the object t. In the destructor or the finalizer, we need to

write the code to release the resources that may be held by the object t.

2.30The Finalization Process

Though finalizer seems to be good to use, it is not advised unless the objects in our

application are using unmanaged resources. The good programming practice is to

avoid Finalize() method, as finalization takes time.

When an object is placed on a heap using new, the CLR automatically

determines whether this object supports a user-defined Finalize() method.

If yes, the object is marked as finalizable and a pointer to this object is stored

on an internal queue names as the finalization queue.

The finalization queue is a table maintained by the CLR that points to every

object that must be finalized before it is removed from the heap.

R.V.COLLEGE OF ENGINEERING Page 256

Page 257: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

When the garbage collector starts its action, it checks every entry on the

finalization queue and copies the object from the heap to another CLR-managed

structure termed as finalization reachable table (f-reachable).

At this moment, a separate thread is produced to invoke the Finalize() method

for each object on the f-reachable table at the next garbage collection.

Thus, when we build a custom-type (user-defined type) that overrides the

System.Object.Finalize() method, the .NET runtime will ensure that this member

is called when our object is removed from the managed heap.

But this will consume time and hence affects the performance of our application.

2.31Building an Ad Hoc Destruction Method

We have seen that the objects holding unmanaged resources can be destroyed

using Finalize() method. But the process of finalization is time consuming. C#

provides an alternative way to avoid this problem of time consumption.

The programmer can write a custom ad hoc method that can be invoked manually

before the object goes out of the scope. This will avoid the object being placed at

finalization queue and avoid waiting for garbage collector to clean-up. The user-

defined method will take care of cleaning up the unmanaged resources.

public class Car

{ …………..

public void Kill() //name of method can be anything

{

//clean up unmanaged resources

}

}

R.V.COLLEGE OF ENGINEERING Page 257

Page 258: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

The IDisposable Interface

In order to provide symmetry among all objects that support an explicit destruction,

the .NET class libraries define an interface named IDisposable. This interface

contains a single member Dispose():

public interface IDisposable

{

public void Dispose();

}

Now, our application can implement this interface and define Dispose() method.

Then, this method can be called manually to release unmanaged resources. Thus,

we can avoid the problems with finalization.

public class Car: IDisposable

{ ………

public void Dispose()

{

//code to clean up unmanaged resources

}

}

class Test

{ ………….

public static void Main()

{

R.V.COLLEGE OF ENGINEERING Page 258

Page 259: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Car c=new Car(“Ford”);

……….

c.Dispose();

………

} //c still remains on heap and may be collected by GC now

}

Thus, another rule for working with garbage collection is:

Always call Dispose() for any object in the heap. The assumption is:

if there is a Dispose() method, the object has some clean up to

perform.

Note that, for a single class, it is possible to have C# - style destructor and also to

implement IDisposable interface for defining Dispose() method.

Reusing the C# using Keyword

When we are using an object that implements IDisposable, it is quite common to

use structured exceptions just to ensure the Dispose() method is called when

exception occurs:

public void Test()

{

Car c=new Car();

try

{

……..

R.V.COLLEGE OF ENGINEERING Page 259

Page 260: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

}

catch{ …….. }

finally

{ ……..

c.Dispose();

}

}

C# provides another way of doing this with the help of using keyword:

public void Test()

{

using(Car c=new Car())

{

//Do something

//Dispose() method is called automatically when this block exits

}

}

One good thing here is, the Dispose() method is called automatically when the

program control comes out of using block. But there is a disadvantage: If at all the

object specified at using does not implement IDisposable, then we will get compile-

time error.

2.32Garbage Collection Optimizations

R.V.COLLEGE OF ENGINEERING Page 260

Page 261: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Till now we have seen two methodologies for cleaning user-defined types. Now, we

will discuss little deeply about the functionality of .NET garbage collector.

When CLR is attempting to locate unreachable objects, it does not literally

search through every object placed on the managed heap looking for orphaned

roots.

Because, doing so will consume more time for larger applications.

To optimize the collection process, each object on the heap is assigned to a

given generation.

The idea behind generation is as follows:

o If an object is on the heap since long time, it means, the object will

continue to exist for more time. For example, application-level objects.

o Conversely, if an object has been recently placed on the heap, it may be

dereferenced by the application quickly. For example, objects within a

scope of a method.

Based on these assumptions, each object belongs to one of the following

generations:

o Generation 0: Identifies a newly allocated object that has never been

marked for collection.

o Generation 1: Identifies an object that has survived a garbage collection

sweep (i.e. it was marked for collection, but was not removed due to the

fact that the heap had enough free space)

o Generation 2: Identifies an object that has survived more than on sweep

of the garbage collector.

Now, when a collection occurs, the GC marks and sweeps all generation 0

objects first.

If required amount of memory is gained, the remaining objects are promoted to

the next available generation.

R.V.COLLEGE OF ENGINEERING Page 261

Page 262: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

To illustrate how an object’s generation affects the collection process, consider the

following diagram –

If all generation 0 objects have been removed from heap and still more memory

is necessary, generation 1 objects are checked for their reachability and

collected accordingly.

Surviving generation 1 objects are then promoted to generation 2.

If the garbage collector still requires additional memory, generation 2 objects are

checked for their reachability.

At this point, if generation 2 objects survive a garbage collection, they remain at

that generation only.

Thus, the newer objects (local variables) are removed quickly and older objects

(application level variables) are assumed to be still in use.

This is how, the GC is able to quickly free heap space using the generation as a

baseline.

R.V.COLLEGE OF ENGINEERING Page 262

A B C D E F G

A B E

Gen 0

Gen 1

Page 263: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

2.33 The System.GC Type

The programmer can interact with the garbage collector using a base class

System.GC. This class provides following members:

System.GC Member Meaning

Collect() Forces the GC to perform a garbage collection.

GetGeneration() Returns the generation to which an object currently belongs.

GetTotalMemory() Returns the estimated amount of memory (in bytes) currently allocated on the managed heap. The Boolean parameter specifies whether the call should wait for garbage collection to occur before returning.

MaxGeneration Returns the maximum of generations supported on the target system. Under Microsoft’s .NET 2.0, there are three possible generations (0, 1, and 2).

SuppressFinalize() Sets a flag indicating that the specified object should not have its Finalize() method called.

WaitForPendingFinalizers() Suspends the current thread until all finalizable objects have been finalized. This method is typically called directly after

R.V.COLLEGE OF ENGINEERING Page 263

Page 264: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

invoking GC.Collect().

Building Finalization and Disposable Types

Consider an example to illustrate how to interact with .NET garbage collector.

using System;

class Car:IDisposable

{

string name;

public Car(string n)

{

name=n;

}

~Car()

{

Console.WriteLine("Within destructor of {0}", name);

}

public void Dispose()

{

Console.WriteLine("Within Dispose() of {0}", name);

GC.SuppressFinalize(this);

R.V.COLLEGE OF ENGINEERING Page 264

Page 265: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

}

}

class Test

{

public static void Main()

{

Car c1=new Car("One");

Car c2=new Car("Two");

Car c3=new Car("Three");

Car c4=new Car("Four");

c1.Dispose();

c3.Dispose();

}

}

Output:

Within Dispose() of One

Within Dispose() of Three

Within destructor of Four

Within destructor of Two

We have discussed earlier that both Dispose() and Finalize() (or destructor)

methods are used to release the unmanaged resources. As we can see in the above

R.V.COLLEGE OF ENGINEERING Page 265

Page 266: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

example, when Dispose() method is invoked through an object, we can prevent the

CLR from calling the corresponding destructor with the help of SuppressFinalize()

method of GC class. By manually calling Dispose() method, we are releasing the

resources and hence there is no need to call finalizer.

Calling the Dispose() function manually is termed as explicit object de-allocation

and making use of finalizer is known as implicit object de-allocation.

Forcing Garbage Collection

We know that, CLR will automatically trigger a garbage collection when a managed

heap is full. We, the programmers, will not be knowing, when this process will

happen. However, if we wish, we can force the garbage collection to occur using the

following statements:

GC.Collect();

GC.WaitForPendingFinalizers();

The method WaitForPendingFinalizers() will allow all finalizable objects to perform

any necessary cleanup before getting destroyed. Though, we can force garbage

collection to occur, it is not a good programming practice.

Interacting with Generations

It is possible to find generation of every object at any moment of time in the

program.

class Car:IDisposable

R.V.COLLEGE OF ENGINEERING Page 266

Page 267: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

{

string name;

public Car(string n)

{

name=n;

}

~Car()

{

Console.WriteLine("Within destructor of {0}", name);

}

public void Dispose()

{

Console.WriteLine("Within Dispose() of {0}", name);

GC.SuppressFinalize(this);

}

}

class Test

{

public static void Main()

{

Car c1=new Car("One");

R.V.COLLEGE OF ENGINEERING Page 267

Page 268: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Car c2=new Car("Two");

Car c3=new Car("Three");

Car c4=new Car("Four");

Console.WriteLine("c1 is Gen {0}", GC.GetGeneration(c1));Console.WriteLine("c2 is Gen {0}", GC.GetGeneration(c2));

Console.WriteLine("c3 is Gen {0}", GC.GetGeneration(c3));

Console.WriteLine("c4 is Gen {0}", GC.GetGeneration(c4));

c1.Dispose();

c3.Dispose();

GC.Collect(0);

Console.WriteLine("c1 is Gen {0}", GC.GetGeneration(c1)); Console.WriteLine("c2 is Gen {0}", GC.GetGeneration(c2));

Console.WriteLine("c3 is Gen {0}", GC.GetGeneration(c3)); Console.WriteLine("c4 is Gen {0}", GC.GetGeneration(c4)); }

}

Output would be –

C1 is Gen 0

C2 is Gen 0

C3 is Gen 0

C4 is Gen 0

Within Dispose() of One

R.V.COLLEGE OF ENGINEERING Page 268

Page 269: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Within Dispose() of Three

C1 is Gen 1

C2 is Gen 1

C3 is Gen 1

C4 is Gen 1

Within Destructor of Four

Within Destructor of Two

Notice that when you request a collection of generation 0, each object is promoted

to generation 1, given that these objects did not need to be removed from memory

(as the heap was not exhausted). Also note that if you request a collection of

generation 2 objects, the object that have survived the current garbage collection

remain at generation 2.

2.34 Summary

In this unit, we have exposed to various aspects of object lifetime. Given hat the

CLR makes use of runtime garbage collections, the basic rule of thumb is to assume

that the runtime will destroy as object when it is no longer needed. However, if your

C# types make use of unmanaged resources that need to be freed in a timely and

predictable manner, you are free to override the virtual System.Object.Finalize()

method and/or implement the IDisposable interface. Finally, you were exposed to be

role of the System.GC type and checked out a subset of its functionality.

2.35 Keywords

Managed Heap

R.V.COLLEGE OF ENGINEERING Page 269

Page 270: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Candidate for garbage collection

newobj Instruction

New Object Pointer

Application Roots

Object Graph

Unmanaged resources

Application Domain (AppDomain)

Finalizable and Finalization Queue

F-reachable table

Finalize() method

IDisposable Interface

The new format of using keyword

Generation

The System.GC class and its members

Explicit and implicit object de-allocation

2.36 Exercises

14.How does .NET framework manage garbage collection? Explain using IDisposable

interface.

15.Explain how garbage collection is optimized in .NET?

16.What are the rules of garbage collection?

17.Define root and explain the role of application roots in garbage collection.

18.Explain the concept of object graph with an example.

19.What is f-reachable table? Explain.

20.Briefly explain the use of using keyword with respect to garbage collection.

21.Explain the concept of generations.

22.When do you override the virtual System.Object.Finalize() method? How to

implement it using destructors?

R.V.COLLEGE OF ENGINEERING Page 270

Page 271: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Module 3

Unit 3

CONTENTS:

1.46 Objectives3.2 Introduction

3.3Defining Interfaces Using C#

3.4Invoking Interface Members at the object level

3.5Exercising the shapes hierarchy

3.6Understanding Explicit Interface Implementation

3.7Interfaces as Polymorphic Agents

3.8 Building Interface Hierarchies

3.9Summary

3.10 Keywords

3.11 Exercises

3.1 Objectives

At the end of this lesson, the students will understand the following tasks in detail:

Meaning of interface

Writing user-defined/custom interface

Defining methods of interface within the implemented classes

Obtaining interface references using three different ways

R.V.COLLEGE OF ENGINEERING Page 271

Page 272: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Passing interfaces as parameters to methods

Explicit interface implementation

Interfaces as polymorphic agents

Building interfaces hierarchies

Interfaces with multiple base interfaces

3.24Introduction

This unit introduces the topic of interface-based programming. Here, you learn how

to use C# to define and implement custom interfaces, and come to understand the

benefits of building types that support multiple behaviors. Along the way, a number

of related topics are also discussed such as obtaining interface references, explicit

interface implementation and the construction of interface hierarchies.

3.25Defining Interfaces using C#

An interface is nothing more than a named collection of semantically related

abstract members. The specific members defined by an interface depend on the

exact behavior it is modeling. An interface expresses a behavior that a given class

or structure may choose to support. At a syntactic level, an interface is defined

using the C# interface keyword. Unlike other .NET types, interfaces never specify a

base class (not even System.Object) and contain members that do not take an

access modifier (as all interface members are implicitly public). Following is an

example showing a custom interface defined in C#:

// This interface defines the behavior of "having points."

public interface IPointy

{

// Implicitly public and abstract.

R.V.COLLEGE OF ENGINEERING Page 272

Page 273: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

byte GetNumberOfPoints();

}

As you can see, the IPointy interface defines a single method. However, .NET

interface types are also able to define any number of properties. For example, you

could create the IPointy interface to use a read-only property rather than a

traditional accessor method:

// The pointy behavior as a read-only property.

public interface IPointy

{

byte Points { get; }

}

Do understand that interface types are quite useless on their own, as they are

nothing more than a named collection of abstract members. Given this, you cannot

allocate interface types as you would a class or structure:

// Ack! Illegal to "new" interface types.

static void Main(string[] args)

{

IPointy p = new IPointy(); // Compiler error!

}

Interfaces do not bring much to the table until they are implemented by a class or

structure. Here, IPointy is an interface that expresses the behavior of “having

points.” As you can tell, this behavior might be useful in the shapes hierarchy

developed in Unit 4 of Module 2. The idea is simple: Some classes in the Shapes

hierarchy have points (such as the Hexagon), while others (such as the Circle) do

not. If you configure Hexagon and Triangle to implement the IPointy interface, you

R.V.COLLEGE OF ENGINEERING Page 273

Page 274: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

can safely assume that each class now supports a common behavior, and therefore

a common set of members.

Implementing an Interface using C#

When a class (or structure) chooses to extend its functionality by supporting

interface types, it does so using a comma-delimited list in the type definition. Be

aware that the direct base class must be the first item listed after the colon

operator. When your class type derives directly from System.Object, you are free to

simply list the interface(s) supported by the class, as the C# compiler will extend

your types from System.Object if you do not say otherwise. On a related note, given

that structures always derive from System.ValueType, simply list each interface

directly after the structure definition. Consider the following examples:

// This class derives from System.Object and implements single interface.

public class SomeClass : ISomeInterface

{...}

//Class derives from custom base class and implements a single interface.

public class AnotherClass : MyBaseClass, ISomeInterface

{...}

// This struct derives from System.ValueType and implements two //interfaces.

public struct SomeStruct : ISomeInterface, IPointy

{...}

Understand that implementing an interface is an all-or-nothing proposition. That is,

one has to define all the members of interface in an implemented class. We can not

R.V.COLLEGE OF ENGINEERING Page 274

Page 275: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

selectively choose which members it will implement. Given that the IPointy interface

defines a single property, this is not too much of a burden. However, if you are

implementing an interface that defines ten members, the type is now responsible

for fleshing out the details of all the ten abstract entities. Here is the

implementation of the updated shapes hierarchy (note the new Triangle class type):

// Hexagon now implements IPointy.

public class Hexagon : Shape, IPointy

{

public Hexagon(){ }

public Hexagon(string name) : base(name){ }

public override void Draw()

{

Console.WriteLine("Drawing {0} the Hexagon", PetName);

}

// IPointy Implementation.

public byte Points

{

get { return 6; }

}

}

// New Shape derived class named Triangle.

public class Triangle : Shape, IPointy

R.V.COLLEGE OF ENGINEERING Page 275

Page 276: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

{

public Triangle() { }

public Triangle(string name) : base(name) { }

public override void Draw()

{

Console.WriteLine("Drawing {0} the Triangle", PetName);

}

// IPointy Implementation.

public byte Points

{

get { return 3; }

}

}

Each class now returns its number of points to the caller when asked to do so.

Following figure illustrates IPointy-compatible classes.

R.V.COLLEGE OF ENGINEERING Page 276

Object

Triangle

Shape

Circle

Hexagon

IPointy

IPointy

Page 277: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Contrasting Interfaces to Abstract Base Classes

By understanding abstract classes earlier, and interfaces now, a question may arise:

what is the need of interface types? After all, C# already allows you to build

abstract class types containing abstract methods. Like an interface, when a class

derives from an abstract base class, it is also under obligation to define the abstract

methods (provided the derived class is not declared abstract as well). However,

abstract base classes do far more than define a group of abstract methods. They

are free to define public, private, and protected state data, as well as any number of

concrete methods that can be accessed by the subclasses.

Interfaces, on the other hand, are pure protocol. Interfaces never define state data

and never provide an implementation of the methods (if you try, you receive a

compile-time error):

public interface IAmABadInterface

{

// Error, interfaces can't define data!

int myInt = 0;

// Error, only abstract members allowed!

void MyMethod()

{

R.V.COLLEGE OF ENGINEERING Page 277

Page 278: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Console.WriteLine("Hi!");

}

}

Interface types are also quite helpful given that C# (and .NET-aware languages in

general) only support single inheritance; the interface-based protocol allows a given

type to support numerous behaviors, while avoiding the issues that arise when

deriving from extending multiple base classes. Most importantly, interface-based

programming provides yet another way to inject polymorphic behavior into a

system. If multiple classes (or structures) implement the same interface in their

unique ways, you have the power to treat each type in the same manner. As you

will see a bit later in this chapter, interfaces are extremely polymorphic, given that

types that are not related via classical inheritance can support identical behaviors.

3.26Invoking Interface Members at the Object Level

Once the methods declared in interfaces are defined within the implemented class,

one can invoke that method using the object of the class. For example:

public static void Main(string[] args)

{

// Call new Points member defined by IPointy

Hexagon hex = new Hexagon();

Console.WriteLine("Points: {0}", hex.Points);

}

This approach works fine in this particular case, given that you are well aware that

the Hexagon type has implemented the interface in question. Other times, however,

you will not be able to determine at compile time which interfaces are supported by

R.V.COLLEGE OF ENGINEERING Page 278

Page 279: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

a given type. For example, assume you have an array containing 50 Shape-

compatible types, only some of which support IPointy. Obviously, if you attempt to

invoke the Points property on a type that has not implemented IPointy, you receive

a compile-time error. Next question: How can we dynamically determine the set of

interfaces supported by a type? This question can be answered in three different

ways as discussed in subsequent sections.

Obtaining Interface References: Explicit Casting

The first way you can determine at runtime if a type supports a specific interface is

to make use of an explicit cast. If the type does not support the requested interface,

you receive an InvalidCastException. To handle this, make use of structured

exception handling, for example:

public static void Main(string[] args)

{

......

// Catch a possible InvalidCastException

Circle c = new Circle("Lisa");

IPointy ipt;

try

{

ipt = (IPointy)c; //boxing or explicit casting

Console.WriteLine(ipt.Points);

}

catch (InvalidCastException e)

{

R.V.COLLEGE OF ENGINEERING Page 279

Page 280: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Console.WriteLine(e.Message);

}

}

While you could make use of try/catch logic and hope for the best, it would be ideal

to determine which interfaces are supported before invoking the interface members

in the first place. So, let’s see the remaining two ways of doing so.

Obtaining Interface References: The as Keyword

The second way you can determine whether a given type supports an interface is to

make use of the as keyword, which was first introduced in Chapter 4. If the object

can be treated as the specified interface, you are returned a reference to the

interface in question. If not, you receive a null reference:

public static void Main(string[] args)

{

...

// Can we treat hex2 as IPointy?

Hexagon h = new Hexagon("Ram");

IPointy ipt = h as IPointy;

if(ipt != null)

Console.WriteLine("Points: {0}", ipt.Points);

else

Console.WriteLine("OOPS! Not pointy...");

}

R.V.COLLEGE OF ENGINEERING Page 280

Page 281: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Notice that when you make use of the as keyword, you have no need to make use

of try/catch logic, given that if the reference is not null, you know you are calling on

a valid interface reference.

Obtaining Interface References: The is Keyword

Finally, you may also obtain an interface from an object using the is keyword. If the

object in question is not IPointy compatible, the condition fails. For example,

//third way to test for an interface

Triangle t = new Triangle();

if(t is IPointy)

Console.WriteLine(t.Points);

else

Console.WriteLine(“OOPS! Not pointy...");

3.27Exercising the Shapes Hierarchy

In these previous examples, you could have avoided checking the outcome of

asking for the IPointy reference, given that you knew ahead of time which shapes

were IPointy compatible. However, what if you were to create an array of generic

Shape references, each of which has been assigned to a given subclass? You may

make use of any of the previous techniques to discover at runtime which items in

the array support this behavior. For example,

public static void Main(string[] args)

R.V.COLLEGE OF ENGINEERING Page 281

Page 282: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

{

...

Shape[ ] s = { new Hexagon(), new Circle(), new Triangle("Ram"), new

Circle("Sham")} ;

for(int i = 0; i < s.Length; i++)

{

// Recall the Shape base class defines an abstract Draw()

// member, so all shapes know how to draw themselves.

s[i].Draw();

if(s[i] is IPointy)

Console.WriteLine("Points: {0} ", ((IPointy)s[i]).Points);

else

Console.WriteLine("{0} is not a pointy!", s[i].PetName);

}

}

Interfaces As Parameters

Given that interfaces are valid .NET types, you may construct methods that take

interfaces as parameters. To illustrate, assume you have defined another interface

named IDraw3D:

// Models the ability to render a type in stunning 3D.

public interface IDraw3D

{

R.V.COLLEGE OF ENGINEERING Page 282

Page 283: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

void Draw3D();

}

Next, assume that two of your three shapes (Circle and Hexagon) have been

configured to support this new behavior:

// Circle supports IDraw3D

public class Circle : Shape, IDraw3D

{

...

public void Draw3D()

{

Console.WriteLine("Drawing Circle in 3D!");

}

}

// Hexagon supports IPointy and IDraw3D

public class Hexagon : Shape, IPointy, IDraw3D

{

...

public void Draw3D()

{

Console.WriteLine("Drawing Hexagon in 3D!");

}

}

R.V.COLLEGE OF ENGINEERING Page 283

Page 284: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

If you now define a method taking an IDraw3D interface as a parameter, you are

able to effectively send in any object implementing IDraw3D (if you attempt to pass

in a type not supporting the necessary interface, you receive a compile-time error).

Consider the following:

// Make some shapes. If they can be rendered in 3D, do it!

public class Program

{

// I'll draw anyone supporting IDraw3D.

public static void DrawIn3D(IDraw3D itf3d)

{

Console.WriteLine("Drawing IDraw3D compatible type");

itf3d.Draw3D();

}

static void Main()

{

Shape[ ] s = { new Hexagon(), new Circle(), new Triangle()};

for(int i = 0; i < s.Length; i++)

{

…..

if(s[i] is IDraw3D)

DrawIn3D((IDraw3D)s[i]);

}

R.V.COLLEGE OF ENGINEERING Page 284

Page 285: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

}

}

Notice that the triangle is never drawn, as it is not IDraw3D-compatible

3.28Understanding Explicit Interface Implementation

In our current definition of IDraw3D, we were forced to name its sole method

Draw3D() in order to avoid clashing with the abstract Draw() method defined in the

Shape base class. While there is nothing horribly wrong with this interface

definition, a more natural method name would simply be Draw():

// Re-factor method name from "Draw3D" to "Draw".

public interface IDraw3D

{

void Draw();

}

If we were to make such a change, this would require us to also update our

implementation of DrawIn3D().

public static void DrawIn3D(IDraw3D itf3d)

{

Console.WriteLine("Drawing IDraw3D compatible type");

itf3d.Draw();

R.V.COLLEGE OF ENGINEERING Page 285

Page 286: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

}

Now, assume you have defined a new class named Line that derives from the

abstract Shape class and implements IDraw3D (both of which now define an

identically named abstract Draw() method):

public class Line : Shape, IDraw3D

{

public override void Draw()

{

Console.WriteLine("Drawing a line...");

}

}

The Line class compiles without a hitch. But consider the following Main() logic:

static void Main(string[] args)

{

...

// Calls Draw().

Line myLine = new Line();

myLine.Draw();

// Calls same implementation of Draw()!

IDraw3D itfDraw3d= (IDraw3D) myLine;

itfDraw3d.Draw();

R.V.COLLEGE OF ENGINEERING Page 286

Page 287: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

}

Given what you already know about the Shape base class and IDraw3D interface, it

looks as if you have called two variations of the Draw() method (one from the object

level, the other from an interface reference). Nevertheless, the compiler is happy to

call the same implementation from an interface or object reference, given that the

Shape abstract base class and IDraw3D interface have an identically named

member. This would be problematic if you would like to have the IDraw3D.Draw()

method to draw a 3D shape, while the overridden Shape.Draw() method draws a

2D. Now consider a related problem. What if you wish to ensure that the methods

defined by a given interface are only accessible from an interface reference rather

than an object reference? Currently, the members defined by the IPointy interface

can be accessed using either an object reference or an IPointy reference. The

answer to both questions comes by way of explicit interface implementation. Using

this technique, you are able to ensure that the object user can only access methods

defined by a given interface using the correct interface reference, as well as

circumvent possible name clashes. To illustrate, here is the updated Line class

(assume you have updated Hexagon and Circle in a similar manner):

// Using explicit method implementation we are able to provide distinct //Draw() implementations.

public class Line : Shape, IDraw3D

{

// this method can be called from an IDraw3D interface reference.

void IDraw3D.Draw()

{

Console.WriteLine("Drawing a 3D line...");

}

R.V.COLLEGE OF ENGINEERING Page 287

Page 288: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

// You can only call this at the object level.

public override void Draw()

{

Console.WriteLine("Drawing a line...");

}

}

As you can see, when explicitly implementing an interface member, the general

pattern breaks down to returnValue InterfaceName.MethodName(args). There are a

few odds and ends to be aware of when using explicit interface implementation.

First and foremost, you cannot define the explicitly implemented members with an

access modifier. For example, the following is illegal syntax:

public class Line : Shape, IDraw3D

{

public void IDraw3D.Draw() // Error!

{

Console.WriteLine("Drawing a 3D line...");

}

...

}

This should make sense. The whole reason to use explicit interface method

implementation is to ensure that a given interface method is bound at the interface

level. If you were to add the public keyword, this would suggest that the method is

a member of the public sector of the class, whichdefeats the point! Given this

design, the caller is only able to invoke the Draw() method defined by the Shape

base class from the object level:

R.V.COLLEGE OF ENGINEERING Page 288

Page 289: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

// This invokes the overridden Shape.Draw() method.

Line myLine = new Line();

myLine.Draw();

To invoke the Draw() method defined by IDraw3D, we must now explicitly obtain the

interface reference using any of the techniques shown previously. For example:

// This triggers the IDraw3D.Draw() method.

Line myLine = new Line();

IDraw3D i3d = (IDraw3D)myLine;

i3d.Draw();

3.29Interfaces as Polymorphic Agents

As you know, an abstract base class containing abstract members allows us to

define a specific behavior that is common across all members in the same class

hierarchy. To understand the usefulness of interfaces, assume that the

GetNumberOFPoints() method was not defined by IPointy, but rather as an abstract

member of the Shape class. if this were the case, Hexagon and Triangle would still

be able to return the correct result. At the same time, Circle would also be obligated

to contend with the GetNumberOfPoints() method as well. In this case, however, it

might seem a bit inelegant to simply return 0.

The problem with defining GetNumberOFPoints() in the Shape base class is that all

derived types must contend with this member, regardless of the semantics. Thus,

the first key point about interfaces is the fact that you can select which members in

the hierarchy support custom behaviors. Also understand that the same interface

R.V.COLLEGE OF ENGINEERING Page 289

Page 290: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

can be implemented by numerous types, even if they are not within the same class

hierarchy in the first place.

3.30Building Interface Hierarchies

To continue our investigation of creating custom interfaces, let’s examine the topic

of interface hierarchies. Just as a class can serve as a base class to other classes

(which can in turn function as base classes to yet another class), it is possible to

build inheritance relationships among interfaces. As you might expect, the topmost

interface defines a general behavior, while the most derived interface defines more

specific behaviors. To illustrate, ponder the following interface hierarchy:

// The base interface.

public interface IDrawable

{

void Draw();

}

public interface IPrintable : IDrawable

{

void Print();

}

public interface IMetaFileRender : IPrintable

{

void Render();

R.V.COLLEGE OF ENGINEERING Page 290

Page 291: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

}

Now, if a class wished to support each behavior expressed in this interface

hierarchy, it would derive from the nth-most interface (IMetaFileRender in this

case). Any methods defined by the base interface(s) are automatically carried into

the definition. For example:

// This class supports IDrawable, IPrintable, and IMetaFileRender.

public class SuperImage : IMetaFileRender

{

public void Draw()

{

Console.WriteLine("Basic drawing logic.");

}

public void Print()

{

Console.WriteLine("Draw to printer.");

}

public void Render()

{

Console.WriteLine("Render to metafile.");

}

}

Here is some sample usage of exercising each interface from a SuperImage

instance:

R.V.COLLEGE OF ENGINEERING Page 291

Page 292: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

// Exercise the interfaces.

static void Main(string[] args)

{

SuperImage si = new SuperImage();

// Get IDrawable.

IDrawable itfDraw = (IDrawable)si;

itfDraw.Draw();

// Now get ImetaFileRender, which exposes all methods up

// the chain of inheritance.

if (itfDraw is IMetaFileRender)

{

IMetaFileRender itfMF = (IMetaFileRender)itfDraw;

itfMF.Render();

itfMF.Print();

}

}

Interfaces with Multiple Base Interfaces

As you build interface hierarchies, be aware that it is completely permissible to

create an interface that derives from multiple base interfaces. Recall, however, that

it is not permissible to build a class that derives from multiple base classes. To

illustrate, assume you are building a new set of interfaces that model the

automobile behaviors for a particular English agent:

R.V.COLLEGE OF ENGINEERING Page 292

Page 293: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

public interface ICar

{

void Drive();

}

public interface IUnderwaterCar

{

void Dive();

}

// Here we have an interface with TWO base interfaces.

public interface IJamesBondCar : ICar, IUnderwaterCar

{

void TurboBoost();

}

If you were to build a class that implements IJamesBondCar, you would now be

responsible for implementing TurboBoost(), Dive(), and Drive():

public class JamesBondCar : IJamesBondCar

{

public void Drive()

{

Console.WriteLine("Speeding up...");

}

public void Dive()

R.V.COLLEGE OF ENGINEERING Page 293

Page 294: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

{

Console.WriteLine("Submerging...");

}

public void TurboBoost()

{

Console.WriteLine("Blast off!");

}

}

This specialized automobile can now be manipulated as you would expect:

static void Main(string[] args)

{

...

JamesBondCar j = new JamesBondCar();

j.Drive();

j.TurboBoost();

j.Dive();

}

3.31Summary

Interface is a collection of abstract members that may be implemented by a given

class. Because an interface does not supply any implantation details, it is common

to regard an interface as a behavior that may be supported by a given type. When

to or more classes implement the same interface, you are able to treat each type in

the same way. This is known an interface-based polymorphism. C# provides the

R.V.COLLEGE OF ENGINEERING Page 294

Page 295: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

keyword interface to allow you to define a new interface. A type can support as

many interfaces as necessary using comma-delimited list. Furthermore, it is

permissible to build interfaces that derive from multiple base interfaces.

3.32 Keywords

Interfaces

Abstract Class

Abstract Members

The keyword is and as

Polymorphism

3.33 Exercises

10. Define an interface. Bring out the differences between interface and abstract

base classes.

11. How do you implement an interface? Explain with an example.

12. Explain different techniques for invoking interface members at the object

level.

13. How do you pass interface as parameter to a method? Explain with an

example.

14. Explain the concept of interface-based polymorphism.

Module 3

Unit 4

CONTENTS:

R.V.COLLEGE OF ENGINEERING Page 295

Page 296: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

1.47 Objectives4.2 Introduction

4.3Understanding the IConvertible Interface

4.4 Building a Custom Enumerator (IEnummerable and Enumerator)

4.5Building Cloneable objects (ICloneable)

4.6Building Comparable Objects (IComparable)

4.7Exploring the System.Collections Namespace

4.8Summary

4.9 Keywords

4.10 Exercises

6.1 Objectives

At the end of this lesson, the students will understand:

The members and implementation of inbuilt interfaces like IConvertible,

IEnumerable, Enumerator, ICloneable and IComparable

The members of System.Collections Namespace and their implementation by

the classes.

4.25Introduction

The previous unit elaborated about the custom interfaces. Here, we will examine

some of the standard interfaces defined within the .NET base class libraries. As we

are going to see, the custom types are free to implement these predefined

interfaces to support a number of advanced behaviors such as object cloning, object

enumeration and object sorting. To wrap things up, we will check out the numerous

R.V.COLLEGE OF ENGINEERING Page 296

Page 297: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

predefined interfaces that are implemented by various collection classes (ArrayList,

Stack etc.) defined by System.Collections namespace.

4.26Understanding the IConvertible Interface

The IConvertible type allows the programmer to dynamically convert between data

types using interface-based programming techniques. Using this interface, one can

cast between types using language-agnostic terms. We know that a majority of the

intrinsic data types of C# (bool, int, double etc) are simply aliases to the structures

in the System namespaces. Like any .NET type, each of these structures may

define any number of methods and may optionally implement any number of

predefined interfaces.

The IConvertible.ToXXXX() Members

The IConvertible interface defines a number of methods of the form ToXXXX(),

which provides a way to convert from one type into another. But sometimes,

conversion may not be possible. For example, converting from Int32 to Double

make sense, whereas, there is no sense in converting Boolean into DateTime. If the

conversion is not supported, then the system will throw InvalidCastException.

Note that, all of the ToXXXX() methods take a parameter of type IFormatProvider.

Objects that implement this interface are able to format their contents based on

culture-specific information. The formal definition would be–

public interface IFormatProvider

{

object GetFormat(Type formatType);

R.V.COLLEGE OF ENGINEERING Page 297

Page 298: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

}

If we are building a custom type that should be formatted using various locals, then

we need to implement IFormatProvider.

IConvertible.GetTypeCode()

The GetTypeCode() method of IConvertible interface is available to any class or

structure which implements IConvertible. This method allows to programmatically

discover a value that represents the type code of the type, which is represented by

the following enumeration:

public enum TypeCode

{

Boolean, Byte, Char, DateTime, DBNull, Decimal, Double, Empty, Int16, Int32, Int64, Object, SByte, Single, String, UInt16, UInt32, UInt64

}

The System.Convert Type

To wrap up this overview of the IConvertible type, it is worth pointing out that the

System namespace defines a type named Convert, which echoes the functionality

of the IConvertible interface. The System.Convert does not directly implement

IConvertible, however, the same set of members are defined on its default public

interface.

4.27Building a Custom Enumerator (IEnumerable and IEnumerator)

R.V.COLLEGE OF ENGINEERING Page 298

Page 299: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Here, we will examine the role of IEnumerable and IEnumerator. Assume you have

developed a class named Garage that contains a set of individual Car types stored

within a System.Array:

// Garage contains a set of Car objects.

public class Garage

{

private Car[] carArray;

// Fill with some Car objects upon startup.

public Garage()

{

carArray = new Car[4];

carArray[0] = new Car("Rusty", 30);

carArray[1] = new Car("Clunker", 55);

carArray[2] = new Car("Zippy", 30);

carArray[3] = new Car("Fred", 30);

}

}

Ideally, it would be convenient to iterate over the Garage object’s sub-items using

the C# foreach construct:

// This seems reasonable...

public class Program

{

static void Main(string[] args)

{

R.V.COLLEGE OF ENGINEERING Page 299

Page 300: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Garage carLot = new Garage();

foreach (Car c in carLot)

{

Console.WriteLine("{0} is going {1} MPH", c.PetName,

c.CurrSpeed);

}

}

}

Sadly, the compiler informs you that the Garage class does not implement a method

named GetEnumerator(). This method is formalized by the IEnumerable interface,

which is found lurking within the System.Collections namespace. Objects that

support this behavior advertise that they are able to expose contained subitems to

the caller:

// This interface informs the caller that the object's subitems can // be enumerated.

public interface IEnumerable

{

IEnumerator GetEnumerator();

}

As you can see, the GetEnumerator() method returns a reference to yet another

interface named System.Collections.IEnumerator. This interface provides the

infrastructure to allow the caller to traverse the internal objects contained by the

IEnumerable-compatible container:

R.V.COLLEGE OF ENGINEERING Page 300

Page 301: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

// This interface allows the caller to obtain a container's subitems.

public interface IEnumerator

{

bool MoveNext (); // Advance the internal position of the cursor.

object Current { get;} // Get the current item (read-only property).

void Reset (); // Reset the cursor before the first member.

}

If you wish to update the Garage type to support these interfaces, you could take

the long road and implement each method manually. While you are certainly free to

provide customized versions of GetEnumerator(), MoveNext(), Current, and Reset(),

there is a simpler way. As the System.Array type (as well as many other types)

already implements IEnumerable and IEnumerator, you can simply delegate the

request to the System.Array as follows:

using System.Collections;

...

public class Garage : IEnumerable

{

// System.Array already implements IEnumerator!

private Car[] carArray;

public Garage()

{

carArray = new Car[4];

carArray[0] = new Car("FeeFee", 200, 0);

R.V.COLLEGE OF ENGINEERING Page 301

Page 302: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

carArray[1] = new Car("Clunker", 90, 0);

carArray[2] = new Car("Zippy", 30, 0);

carArray[3] = new Car("Fred", 30, 0);

}

public IEnumerator GetEnumerator()

{

// Return the array object's IEnumerator.

return carArray.GetEnumerator();

}

}

Once you have updated your Garage type, you can now safely use the type within

the C# foreach construct. Furthermore, given that the GetEnumerator() method has

been defined publicly, the object user could also interact with the IEnumerator type:

// Manually work with IEnumerator.

IEnumerator i = carLot.GetEnumerator();

i.MoveNext();

Car myCar = (Car)i.Current;

Console.WriteLine("{0} is going {1} MPH", myCar.PetName,

myCar.CurrSpeed);

If you would prefer to hide the functionality of IEnumerable from the object level,

simply make use of explicit interface implementation:

R.V.COLLEGE OF ENGINEERING Page 302

Page 303: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

public IEnumerator IEnumerable.GetEnumerator()

{

// Return the array object's IEnumerator.

return carArray.GetEnumerator();

}

4.28Building Cloneable Objects (ICloneable)

As you recall from earlier discussion, System.Object defines a member named

MemberwiseClone(). This method is used to obtain a shallow copy of the current

object. Object users do not call this method directly (as it is protected); however, a

given object may call this method itself during the cloning process. To illustrate,

assume you have a class named Point:

// A class named Point.

public class Point

{

// Public for easy access.

public int x, y;

public Point(int x, int y) { this.x = x; this.y = y;}

public Point(){}

// Override Object.ToString().

public override string ToString()

{

return string.Format("X = {0}; Y = {1}", x, y );

R.V.COLLEGE OF ENGINEERING Page 303

Page 304: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

}

}

Given what you already know about reference types and value types, you are aware

that if you assign one reference variable to another, you have two references

pointing to the same object in memory. Thus, the following assignment operation

results in two references to the same Point object on the heap; modifications using

either reference affect the same object on the heap:

static void Main(string[] args)

{

// Two references to same object!

Point p1 = new Point(50, 50);

Point p2 = p1;

p2.x = 0;

Console.WriteLine(p1);

Console.WriteLine(p2);

}

When you wish to equip your custom types to support the ability to return an

identical copy of itself to the caller, you may implement the standard ICloneable

interface. This type defines a single method named Clone():

public interface ICloneable

{

object Clone();

}

R.V.COLLEGE OF ENGINEERING Page 304

Page 305: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Obviously, the implementation of the Clone() method varies between objects.

However, the basic functionality tends to be the same: Copy the values of your

member variables into a new object instance, and return it to the user. To illustrate,

ponder the following update to the Point class:

// The Point now supports "clone-ability."

public class Point : ICloneable

{

public int x, y;

public Point(){ }

public Point(int x, int y)

{

this.x = x; this.y = y;

}

// Return a copy of the current object.

public object Clone()

{

return new Point(this.x, this.y);

}

public override string ToString()

{

return string.Format("X = {0}; Y = {1}", x, y );

}

}

R.V.COLLEGE OF ENGINEERING Page 305

Page 306: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

In this way, you can create exact stand-alone copies of the Point type, as illustrated

by the following code:

static void Main(string[] args)

{

// Notice Clone() returns a generic object type.

// You must perform explicit cast to obtain the derived type.

Point p3 = new Point(100, 100);

Point p4 = (Point)p3.Clone();

// Change p4.x (which will not change p3.x).

p4.x = 0;

// Print each object.

Console.WriteLine(p3);

Console.WriteLine(p4);

}

While the current implementation of Point fits the bill, you can streamline things just

a bit. Because the Point type does not contain reference type variables, you could

simplify the implementation of the Clone() method as follows:

public object Clone()

{

// Copy each field of the Point member by member.

return this.MemberwiseClone();

}

R.V.COLLEGE OF ENGINEERING Page 306

Page 307: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Be aware, however, that if the Point did contain any reference type member

variables, MemberwiseClone() will copy the references to those objects (aka a

shallow copy). If you wish to support a true deep copy, you will need to create a

new instance of any reference type variables during the cloning process. Let’s see

an example.

A More Elaborate Cloning Example

Now assume the Point class contains a reference type member variable of type

PointDescription. This class maintains a point’s friendly name as well as an

identification number expressed as a System.Guid (Globally Unique Identifier [GUID]

is a statistically unique 128-bit number). Here is the implementation:

// This class describes a point.

public class PointDescription

{

// Exposed publicly for simplicity.

public string petName;

public Guid pointID;

public PointDescription()

{

this.petName = "No-name";

pointID = Guid.NewGuid();

}

}

The initial updates to the Point class itself included modifying ToString() to account

for these new bits of state data, as well as defining and creating the

R.V.COLLEGE OF ENGINEERING Page 307

Page 308: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

PointDescription reference type. To allow the outside world to establish a pet name

for the Point, you also update the arguments passed into the overloaded

constructor:

public class Point : ICloneable

{

public int x, y;

public PointDescription desc = new PointDescription();

public Point(){ }

public Point(int x, int y)

{

this.x = x; this.y = y;

}

public Point(int x, int y, string petname)

{

this.x = x;

this.y = y;

desc.petName = petname;

}

public object Clone()

{

return this.MemberwiseClone();

}

public override string ToString()

{

R.V.COLLEGE OF ENGINEERING Page 308

Page 309: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

return string.Format("X = {0}; Y = {1}; Name = {2};\n ID =

{3}\n", x, y, desc.petName, desc.pointID);

}

}

Notice that you did not yet update your Clone() method. Therefore, when the object

user asks for a clone using the current implementation, a shallow (member-by-

member) copy is achieved. To illustrate, assume you have updated Main() as

follows:

static void Main(string[] args)

{

Console.WriteLine("Cloned p3 and stored new Point in p4");

Point p3 = new Point(100, 100, "Jane");

Point p4 = (Point)p3.Clone();

Console.WriteLine("Before modification:");

Console.WriteLine("p3: {0}", p3);

Console.WriteLine("p4: {0}", p4);

p4.desc.petName = "Mr. X";

p4.x = 9;

Console.WriteLine("\nChanged p4.desc.petName and p4.x");

Console.WriteLine("After modification:");

Console.WriteLine("p3: {0}", p3);

Console.WriteLine("p4: {0}", p4);

}

R.V.COLLEGE OF ENGINEERING Page 309

Page 310: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

In order for your Clone() method to make a complete deep copy of the internal

reference types, you need to configure the object returned by MemberwiseClone() t

o account for the current point’s name (the System.Guid type is in fact a structure,

so the numerical data is indeed copied). Here is one possible implementation:

// Now we need to adjust for the PointDescription member.

public object Clone()

{

Point newPoint = (Point)this.MemberwiseClone();

PointDescription currentDesc = new PointDescription();

currentDesc.petName = this.desc.petName;

newPoint.desc = currentDesc;

return newPoint;

}

If you rerun the application once again as shown in Figure 7-9, you see that the

Point returned from Clone() does copy its internal reference type member variables

(note the pet name is now unique for both p3 and p4).

To summarize the cloning process, if you have a class or structure that contains

nothing but value types, implement your Clone() method using MemberwiseClone().

However, if you have a custom type that maintains other reference types, you need

to establish a new type that takes into account each reference type member

variable.

4.29Building Comparable Objects (IComparable)

R.V.COLLEGE OF ENGINEERING Page 310

Page 311: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

The System.IComparable interface specifies a behavior that allows an object to be

sorted based on some specified key. Here is the formal definition:

// This interface allows an object to specify its relationship //between other like objects.

public interface IComparable

{

int CompareTo(object o);

}

Let’s assume you have updated the Car class to maintain an internal ID number

(represented by a simple integer named carID) that can be set via a constructor

parameter and manipulated using a new property named ID. Here are the relevant

updates to the Car type:

public class Car

{

...

private int carID;

public int ID

{

get { return carID; }

set { carID = value; }

}

public Car(string name, int currSp, int id)

{

currSpeed = currSp;

petName = name;

R.V.COLLEGE OF ENGINEERING Page 311

Page 312: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

carID = id;

}

...

}

Object users might create an array of Car types as follows:

static void Main(string[] args)

{

// Make an array of Car types.

Car[] myAutos = new Car[5];

myAutos[0] = new Car("Rusty", 80, 1);

myAutos[1] = new Car("Mary", 40, 234);

myAutos[2] = new Car("Viper", 40, 34);

myAutos[3] = new Car("Mel", 40, 4);

myAutos[4] = new Car("Chucky", 40, 5);

}

As you recall, the System.Array class defines a static method named Sort(). When

you invoke this method on an array of intrinsic types (int, short, string, etc.), you

are able to sort the items in the array in numerical/alphabetic order as these

intrinsic data types implement IComparable. However, what if you were to send an

array of Car types into the Sort() method as follows?

// Sort my cars?

Array.Sort(myAutos);

If you run this test, you would find that an ArgumentException exception is thrown

by the runtime, with the following message: “At least one object must implement

R.V.COLLEGE OF ENGINEERING Page 312

Page 313: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

IComparable.” When you build custom types, you can implement IComparable to

allow arrays of your types to be sorted. When you flesh out the details of

CompareTo(), it will be up to you to decide what the baseline of the ordering

operation will be. For the Car type, the internal carID seems to be the most logical

candidate:

// The iteration of the Car can be ordered based on the CarID.

public class Car : IComparable

{

...

// IComparable implementation.

int IComparable.CompareTo(object obj)

{

Car temp = (Car)obj;

if(this.carID > temp.carID)

return 1;

if(this.carID < temp.carID)

return -1;

else

return 0;

}

}

As you can see, the logic behind CompareTo() is to test the incoming type against

the current instance based on a specific point of data. The return value of

CompareTo() is used to discover if this type is less than, greater than, or equal to

the object it is being compared with (see the following table).

R.V.COLLEGE OF ENGINEERING Page 313

Page 314: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

CompareTo() Return Value Meaning

Any number less than zero This instance comes before the specified object in the sort order.

Zero This instance is equal to the specified object.

Any number greater than zero This instance comes after the specified object in the sort order.

Now that your Car type understands how to compare itself to like objects, you can

write the following user code:

// Exercise the IComparable interface.

static void Main(string[] args)

{

// Make an array of Car types.

...

// Dump current array.

Console.WriteLine("Here is the unordered set of cars:");

foreach(Car c in myAutos)

Console.WriteLine("{0} {1}", c.ID, c.PetName);

// Now, sort them using IComparable!

Array.Sort(myAutos);

// Dump sorted array.

Console.WriteLine("Here is the ordered set of cars:");

foreach(Car c in myAutos)

Console.WriteLine("{0} {1}", c.ID, c.PetName);

R.V.COLLEGE OF ENGINEERING Page 314

Page 315: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Console.ReadLine();

}

4.30Exploring the System.Collections Namespace

We know that the System.Array class provides a number of services (e.g., reversing,

sorting, clearing, and enumerating). However, the simple Array class has a number

of limitations, most notably it does not dynamically resize itself as you add or clear

items. When you need to contain types in a more flexible container, you may wish

to leverage the types defined within the System.Collections namespace.

The System.Collections namespace defines a number of interfaces. As you can

guess, a majority of the collection classes implement these interfaces to provide

access to their contents. Following table gives a breakdown of the core collection-

centric interfaces.

System.Collections

Interface

Meaning

ICollection Defines generic characteristics (e.g., count and thread safety) for a collection type.

IComparer Defines methods to support the comparison of objects for equality.

IDictionary Allows an object to represent its contents using name/value pairs.

IDictionaryEnumerator Enumerates the contents of a type supporting

R.V.COLLEGE OF ENGINEERING Page 315

Page 316: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

IDictionary.

IEnumerable Returns the IEnumerator interface for a given object.

IEnumerator Generally supports foreach-style iteration of subtypes.

IHashCodeProvider Returns the hash code for the implementing type using a customized hash algorithm.

IList Provides behavior to add, remove, and index items in a list of objects.

Following figure illustrates the relationship between each type of the interfaces:

The Class Types of System.Collections

We, know that interfaces by themselves are not very useful until they are

implemented by a given class or structure. The following table provides a rundown

R.V.COLLEGE OF ENGINEERING Page 316

IHashCodeProvider IEnumerator

IDictionaryEnumeratorIComparer

IDictionaryIList

IEnumerable

ICollection

Page 317: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

of the core classes in the System.Collections namespace and the key interfaces

they support.

System.Collections Class

Meaning Key Implemented

Interfaces

ArrayList Represents a dynamically sized array of objects.

IList, ICollection,

IEnumerable, and ICloneable

Hashtable Represents a collection of objects identified by a numerical key. Custom types stored in a Hashtable should always override

System.Object.GetHashCode().

IDictionary, ICollection, IEnumerable, and ICloneable

Queue Represents a standard first-in, first-out (FIFO) queue.

ICollection, ICloneable, and IEnumerable

SortedList Like a dictionary; however, the elements can also be accessed by ordinal position (e.g., index).

IDictionary, ICollection, IEnumerable, and ICloneable

Stack A last-in, first-out (LIFO) queue providing push and pop (and peek) functionality.

ICollection, ICloneable, and

IEnumerable

In addition to these key types, System.Collections defines some minor players (at

least in terms of their day-to-day usefulness) such as BitArray,

CaseInsensitiveComparer, and CaseInsensitiveHashCodeProvider. Furthermore, this

namespace also defines a small set of abstract base classes (CollectionBase,

R.V.COLLEGE OF ENGINEERING Page 317

Page 318: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

ReadOnlyCollectionBase, and DictionaryBase) that can be used to build strongly

typed containers.

Working with the ArrayList Type

The ArrayList type is bound to be your most frequently used type in the

System.Collections namespace in that it allows you to dynamically resize the

contents at your whim. To illustrate the basics of this type, ponder the following

code, which leverages the ArrayList to manipulate a set of Car objects:

static void Main(string[] args)

{

// Create ArrayList and fill with some initial values.

ArrayList carArList = new ArrayList();

carArList.AddRange(new Car[ ] { new Car("Fred", 90, 10),

new Car("Mary", 100, 50), new Car("MB", 190, 11)});

Console.WriteLine("Items in carArList: {0}", carArList.Count);

// Print out current values.

foreach(Car c in carArList)

Console.WriteLine("Car pet name: {0}", c.PetName);

// Insert a new item.

Console.WriteLine("\n->Inserting new Car.");

carArList.Insert(2, new Car("TheNewCar", 0, 12));

Console.WriteLine("Items in carArList: {0}", carArList.Count);

R.V.COLLEGE OF ENGINEERING Page 318

Page 319: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

// Get object array from ArrayList and print again.

object[] arrayOfCars = carArList.ToArray();

for(int i = 0; i < arrayOfCars.Length; i++)

{

Console.WriteLine("Car pet name: {0}",

((Car)arrayOfCars[i]).PetName);

}

}

Here you are making use of the AddRange() method to populate your ArrayList with

a set of Car types (this is basically a shorthand notation for calling Add() n number

of times). Once you print out the number of items in the collection (as well as

enumerate over each item to obtain the pet name), you invoke Insert(). The Insert()

allows you to plug a new item into the ArrayList at a specified index. Finally, notice

the call to the ToArray() method, which returns a generic array of System.Object

types based on the contents of the original ArrayList.

Working with the Queue Type

Queues are containers that ensure items are accessed using a first-in, first-out

manner. Sadly, we humans are subject to queues all day long: lines at the bank,

lines at the movie theater, and lines at the morning coffeehouse. When you are

modeling a scenario in which items are handled on a first-come, first-served basis,

System.Collections.Queue is your type of choice. In addition to the functionality

provided by the supported interfaces, Queue defines the key members shown in the

following table.

Member of Meaning

R.V.COLLEGE OF ENGINEERING Page 319

Page 320: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

System.Collection.Queue

Dequeue() Removes and returns the object at the beginning of the Queue

Enqueue() Adds an object to the end of the Queue

Peek() Returns the object at the beginning of the Queue without removing it

Working with the Stack Type

The System.Collections.Stack type represents a collection that maintains items

using a last-in, first-out manner. As you would expect, Stack defines a member

named Push() and Pop() (to place items onto or remove items from the stack). The

following stack example makes use of the standard System.String:

static void Main(string[] args)

{

...

Stack stringStack = new Stack();

stringStack.Push("One");

stringStack.Push("Two");

stringStack.Push("Three");

// Now look at the top item, pop it, and look again.

Console.WriteLine("Top item is: {0}", stringStack.Peek());

Console.WriteLine("Popped off {0}", stringStack.Pop());

Console.WriteLine("Top item is: {0}", stringStack.Peek());

Console.WriteLine("Popped off {0}", stringStack.Pop());

Console.WriteLine("Top item is: {0}", stringStack.Peek());

R.V.COLLEGE OF ENGINEERING Page 320

Page 321: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Console.WriteLine("Popped off {0}", stringStack.Pop());

try

{

Console.WriteLine("Top item is: {0}", stringStack.Peek());

Console.WriteLine("Popped off {0}", stringStack.Pop());

}

catch(Exception e)

{ Console.WriteLine("Error!! {0}", e.Message); }

}

Here, you build a stack that contains three string types (named according to their

order of insertion). As you peek onto the stack, you will always see the item at the

very top, and therefore the first call to Peek() reveals the third string. After a series

of Pop() and Peek() calls, the stack is eventually empty, at which time additional

Peek()/Pop() calls raise a system exception.

4.31Summary

In addition to building you custom interfaces, the .NET libraries define a number of

standard (i.e. framework-supplied) interfaces. This unit focused on the interfaces

defined within the System.Collections namespace. As you have seen, you are free

to build custom types that implement these predefined interfaces to gain a number

of desirable traits such as cloning, sorting and enumerating.

4.32Keywords

IConvertible.ToXXXX() method IFormatProvider Interface GetFormat() method IConvertible.GetTypeCode() method

R.V.COLLEGE OF ENGINEERING Page 321

Page 322: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

System.Convert GetEnumerator() method Clone() method GUID CompareTo() method The classes: ArrayList, Hashtable, Queue, SortedList, Stack

4.33 Exercises

23.Explain any two methods of IConvertible interface.

24.Explain the usage of IEnumerable and IEnumerator interfaces with suitable

examples.

25.What do you mean by cloneable object? Write an example to depict the

implementation of ICloneable Interface.

26.Illustrate with an example, the implementation of IComparable interface.

27.Give the syntax for the method CompareTo() and explain briefly.

28.List out some of the interfaces provided by System.Collection namespace.

Draw the diagram to show the hierarchical relationship that exists between

these interfaces.

29.What are the major classes in System.Collections namespace? Explain.

30.Write a code segment to illustrate the working of ArrayList class.

31.What the members of System.Collection.Queue? Explain.

32.Write a code snippet to show the usage of Stack class.

Module 4

Unit 1

CONTENTS:

1.48 Objectives

R.V.COLLEGE OF ENGINEERING Page 322

Page 323: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

1.49 Introduction1.50 Understanding Callback Interfaces1.51 Understanding the .NET Delegate Type1.52 Members of System.Multicast Delegate1.53 The Simplest Possible Delegate Example1.54 Building More Elaborate Delegate Example1.55 Understanding Asynchronous Delegates1.56 Understanding (and Using) Events 1.57 Summary1.58 Keywords1.59 Exercises

1.40 Objectives

At the end of this lesson, the students will understand:

The meaning of callback interfaces and its usage

Delegate types, their usage, members of Multicast delegate, synchronous

and asynchronous delegates

Events

1.41 Introduction

Up to this point in the text, every application you have developed added various

bits of code to Main(), which, in some way or another, sent requests to a given

object. However, you have not yet examined how an object can talk back to the

entity that created it. In most programs, it is quite common for objects in a system

to engage in a two-way conversation through the use of callback interfaces, events,

and other programming constructs. To set the stage, this chapter begins by

examining how interface types may be used to enable callback functionality.

Next, you learn about the .NET delegate type, which is a type-safe object that

“points to” other method(s) that can be invoked at a later time. Unlike a traditional

R.V.COLLEGE OF ENGINEERING Page 323

Page 324: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

C++ function pointer, however, .NET delegates are objects that have built-in

support for multicasting and asynchronous method invocation. Once you learn how

to create and manipulate delegate types, you then investigate the C# event

keyword, which simplifies and streamlines the process of working with delegate

types.

1.42 Understanding Callback Interfaces

As you have seen in the previous module, interfaces define a behavior that may be

supported by various types in your system. Beyond using interfaces to establish

polymorphism, interfaces may also be used as a callback mechanism. This

technique enables objects to engage in a two-way conversation using a common set

of members. To illustrate the use of callback interfaces, let’s update the now

familiar Car type in such a way that it is able to inform the caller when it is about to

explode (the current speed is 10 miles below the maximum speed) and has

exploded (the current speed is at or above the maximum speed). The ability to send

and receive these events will be facilitated with a custom interface named

IEngineEvents:

// The callback interface.

public interface IEngineEvents

{

void AboutToBlow(string msg);

void Exploded(string msg);

}

Event interfaces are not typically implemented directly by the object directly

interested in receiving the events, but rather by a helper object called a sink object.

R.V.COLLEGE OF ENGINEERING Page 324

Page 325: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

The sender of the events (the Car type in this case) will make calls on the sink

under the appropriate circumstances. Assume the sink class is called CarEventSink,

which simply prints out the incoming messages to the console. Beyond this point,

our sink will also maintain a string that identifies its friendly name:

// Car event sink.

public class CarEventSink : IEngineEvents

{

private string name;

public CarEventSink(){ }

public CarEventSink(string sinkName)

{ name = sinkName; }

public void AboutToBlow(string msg)

{ Console.WriteLine("{0} reporting: {1}", name, msg); }

public void Exploded(string msg)

{ Console.WriteLine("{0} reporting: {1}", name, msg); }

}

Now that you have a sink object that implements the event interface, your next task

is to pass a reference to this sink into the Car type. The Car holds onto the

reference and makes calls back on the sink when appropriate. In order to allow the

Car to obtain a reference to the sink, we will need to add a public helper member to

the Car type that we will call Advise(). Likewise, if the caller wishes to detach from

the event source, it may call another helper method on the Car type named

Unadvise(). Finally, in order to allow the caller to register multiple event sinks (for

the purposes of multicasting), the Car now maintains an ArrayList to represent each

outstanding connection:

R.V.COLLEGE OF ENGINEERING Page 325

Page 326: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

// This Car and caller can now communicate

// using the IEngineEvents interface.

public class Car

{

// The set of connected sinks.

ArrayList clientSinks = new ArrayList();

// Attach or disconnect from the source of events.

public void Advise(IEngineEvents sink)

{ clientSinks.Add(sink); }

public void Unadvise(IEngineEvents sink)

{ clientSinks.Remove(sink); }

...

}

To actually send the events, let’s update the Car.Accelerate() method to iterate

over the list of connections maintained by the ArrayList and fire the correct

notification when appropriate (note the Car class now maintains a Boolean member

variable named carIsDead to represent the engine’s state):

// Interface-based event protocol!

class Car

{

...

// Is the car alive or dead?

bool carIsDead;

R.V.COLLEGE OF ENGINEERING Page 326

Page 327: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

public void Accelerate(int delta)

{

// If the car is 'dead', send Exploded event to each sink.

if(carIsDead)

{

foreach(IEngineEvents e in clientSinks)

e.Exploded("Sorry, this car is dead...");

}

else

{

currSpeed += delta;

// Send AboutToBlow event.

if(10 == maxSpeed - currSpeed)

{

foreach(IEngineEvents e in clientSinks)

e.AboutToBlow("Careful !!!");

}

if(currSpeed >= maxSpeed)

carIsDead = true;

else

Console.WriteLine("CurrSpeed= {0} ", currSpeed);

}

}

}

R.V.COLLEGE OF ENGINEERING Page 327

Page 328: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Here is some client-side code, now making use of a callback interface to listen to

the Car events:

// Make a car and listen to the events.

public class CarApp

{

static void Main(string[] args)

{

Console.WriteLine("***** Interfaces as event enablers *****");

Car c1 = new Car("SlugBug", 100, 10);

// Make sink object.

CarEventSink sink = new CarEventSink();

// Pass the Car a reference to the sink.

c1.Advise(sink);

// Speed up (this will trigger the events).

for(int i = 0; i < 10; i++)

c1.Accelerate(20);

// Detach from event source.

c1.Unadvise(sink);

Console.ReadLine();

}

}

R.V.COLLEGE OF ENGINEERING Page 328

Page 329: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Do note that the Unadvise() method can be very helpful in that it allows the caller to

selectively detach from an event source at will. Here, you call Unadvise() before

exiting Main(), although this is not technically necessary. However, assume that the

application now wishes to register two sinks, dynamically remove a particular sink

during the flow of execution, and continue processing the program at large.

1.43 Understanding the .NET Delegate Type

Before formally defining .NET delegates, let’s gain a bit of perspective. Historically

speaking, the Windows API makes frequent use of C-style function pointers to create

entities termed callback functions or simply callbacks. Using callbacks,

programmers were able to configure one function to report back to (call back)

another function in the application. The problem with standard C-style callback

functions is that they represent little more than a raw address in memory. Ideally,

callbacks could be configured to include additional type-safe information such as

the number of (and types of) parameters and the return value (if any) of the method

pointed to. Sadly, this is not the case in traditional callback functions, and, as you

may suspect, can therefore be a frequent source of bugs, hard crashes, and other

runtime disasters. Nevertheless, callbacks are useful entities. In the .NET

Framework, callbacks are still possible, and their functionality is accomplished in a

much safer and more object-oriented manner using delegates. In essence, a

delegate is a type-safe object that points to another method (or possibly multiple

methods) in the application, which can be invoked at a later time. Specifically

speaking, a delegate type maintains three important pieces of information:

The name of the method on which it makes calls The arguments (if any) of this method The return value (if any) of this method

Once a delegate has been created and provided the aforementioned information, it

may dynamically invoke the method(s) it points to at runtime. As you will see, every

delegate in the .NET Framework (including your custom delegates) is automatically

endowed with the ability to call their methods synchronously or asynchronously.

R.V.COLLEGE OF ENGINEERING Page 329

Page 330: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

This fact greatly simplifies programming tasks, given that we can call a method on a

secondary thread of execution without manually creating and managing a Thread

object.

Defining a Delegate in C#

When you want to create a delegate in C#, you make use of the delegate keyword.

The name of your delegate can be whatever you desire. However, you must define

the delegate to match the signature of the method it will point to. For example,

assume you wish to build a delegate named BinaryOp that can point to any method

that returns an integer and takes two integers as input parameters:

// This delegate can point to any method, taking two integers

// and returning an integer.

public delegate int BinaryOp(int x, int y);

When the C# compiler processes delegate types, it automatically generates a

sealed class deriving from System.MulticastDelegate. This class (in conjunction with

its base class, System.Delegate) provides the necessary infrastructure for the

delegate to hold onto the list of methods to be invoked at a later time.

1.44 Members of System.MulticastDelegate

When you build a type using the C# delegate keyword, you indirectly declare a

class type that derives from System.MulticastDelegate. This class provides

descendents with access to a list that contains the addresses of the methods

maintained by the delegate type, as well as several additional methods (and a few

overloaded operators) to interact with the invocation list. Here are some select

members of System.MulticastDelegate:

R.V.COLLEGE OF ENGINEERING Page 330

Page 331: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Inherited Member

Meaning

Method This property returns a System.Reflection.MethodInfo type that represents details of a static method that is maintained by the delegate.

Target If the method to be called is defined at the object level (rather than a static method), Target returns an object that represents the method maintained by the delegate. If the value returned from Target equals null, the method to be called is a static member.

Combine() This static method adds a method to the list maintained by the delegate. In C#, you trigger this method using the overloaded += operator as

a shorthand notation.

GetInvocationList() This method returns an array of System.Delegate types, each representing a particular method that may be invoked.

Remove()

RemoveAll()

These static methods remove a method (or all methods) from the invocation list. In C#, the Remove() method can be called indirectly using

the overloaded -= operator.

1.45 The Simplest Possible Delegate Example

Delegates can tend to cause a great deal of confusion when encountered for the

first time. Thus, to get the ball rolling, let’s take a look at a very simple example

that leverages our BinaryOp delegate type. Here is the complete code, with analysis

to follow:

R.V.COLLEGE OF ENGINEERING Page 331

Page 332: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

namespace SimpleDelegate

{

// This delegate can point to any method, taking two

// integers and returning an integer.

public delegate int BinaryOp(int x, int y);

// This class contains methods BinaryOp will point to.

public class SimpleMath

{

public static int Add(int x, int y)

{ return x + y; }

public static int Subtract(int x, int y)

{ return x – y; }

}

class Program

{

static void Main(string[] args)

{

Console.WriteLine("Simple Delegate Example");

// Create a BinaryOp object that

// "points to" SimpleMath.Add().

BinaryOp b = new BinaryOp(SimpleMath.Add);

// Invoke Add() method using delegate.

Console.WriteLine("10 + 10 is {0}", b(10, 10));

Console.ReadLine();

R.V.COLLEGE OF ENGINEERING Page 332

Page 333: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

}

}

}

Again notice the format of the BinaryOp delegate, which can point to any method

taking two integers and returning an integer. Given this, we have created a class

named SimpleMath, which defines two static methods that match the pattern

defined by the BinaryOp delegate. When you want to insert the target method to a

given delegate, simply pass in the name of the method to the delegate’s

constructor. At this point, you are able to invoke the member pointed to using a

syntax that looks like a direct function invocation:

// Invoke() is really called here!

Console.WriteLine("10 + 10 is {0}", b(10, 10));

Under the hood, the runtime actually calls the compiler-generated Invoke() method.

Recall that .NET delegates (unlike C-style function pointers) are type safe.

Therefore, if you attempt to pass a delegate a method that does not “match the

pattern,” you receive a compile-time error. To illustrate, assume the SimpleMath

class defines an additional method named SquareNumber():

public class SimpleMath

{

...

public static int SquareNumber(int a)

{ return a * a; }

}

R.V.COLLEGE OF ENGINEERING Page 333

Page 334: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Given that the BinaryOp delegate can only point to methods that take two integers

and return an integer, the following code is illegal and will not compile:

// Error! Method does not match delegate pattern!

BinaryOp b = new BinaryOp(SimpleMath.SquareNumber);

1.46 Building a More Elaborate Delegate Example

To illustrate a more advanced use of delegates, let’s begin by updating the Car

class to include two new Boolean member variables. The first is used to determine

whether your automobile is due for a wash (isDirty); the other represents whether

the car in question is in need of a tire rotation (shouldRotate). To enable the object

user to interact with this new state data, Car also defines some additional

properties and an updated constructor. Here is the story so far:

// Updated Car class.

public class Car

{

...

// Are we in need of a wash? Need to rotate tires?

private bool isDirty;

private bool shouldRotate;

// Extra params to set bools.

public Car(string name, int max, int curr, bool washCar, bool rotateTires)

{

...

R.V.COLLEGE OF ENGINEERING Page 334

Page 335: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

isDirty = washCar;

shouldRotate = rotateTires;

}

public bool Dirty

{

get{ return isDirty; }

set{ isDirty = value; }

}

public bool Rotate

{

get{ return shouldRotate; }

set{ shouldRotate = value; }

}

}

Now, also assume the Car type nests a new delegate, CarDelegate:

// Car defines yet another delegate.

public class Car

{

...

// Can call any method taking a Car as

// a parameter and returning nothing.

public delegate void CarDelegate(Car c);

...

}

R.V.COLLEGE OF ENGINEERING Page 335

Page 336: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Here, you have created a delegate named CarDelegate. The CarDelegate type

represents “some function” taking a Car as a parameter and returning void.

1.47 Understanding Asynchronous Delegates

Till now, we have seen the synchronous behavior of .NET delegate types. Now let

us examine how to invoke methods asynchronously. First off, what exactly warrants

an asynchronous method invocation? As you are aware, some programming

operations take time. For example, if you build a word processing application that

has the ability to print the current document, and that document happens to be

1000 pages in length, the computer’s CPU has the potential to spin away for quite

some time.

Now assume that this application has all of its programming logic taking place

within the Main() method using a single thread. Simply put, a thread is a path of

execution within a .NET application. Single-threaded applications are quite simple

to program; however, in the case of word processor application, the end user is far

less than pleased. The reason has to do with the fact that while the application’s

single thread of execution is crunching out the 1000-page document, all other

aspects of this program (such as menu activation, toolbar clicking, and keyboard

input) are unresponsive.

When programmers wish to build applications that are able to simulate numerous

tasks performing “at the same time”, they will typically spawn additional threads to

R.V.COLLEGE OF ENGINEERING Page 336

Page 337: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

perform background tasks (e.g. printing documents) while the main thread is still

able to respond to basic user-input needs.

So, what does threading have to do with .NET delegates? Well, to illustrate the

potential problem with synchronous delegate invocations, consider the following

application:

using System;

using System.Threading;

namespace AsyncDelegate

{

// a new delegate type

public delegate string NewCarDelegate(Car carToDetail);

public class Car { ….}

class App

{

public static stirng DetailCar(Car c)

{

//Detailing a car takes 10 seconds

Console.WriteLine(“Detailing Car on Thread {0}”,

Thread.CurrentThread.GetHashCode());

Thread.Sleep(10000);

return “Your car is ready!!”;

R.V.COLLEGE OF ENGINEERING Page 337

Page 338: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

}

static void Main(string[] args)

{

Console.WriteLine(“Main() is on thread {0}”,

Thread.CurrentThread.GetHashCode());

NewCarDelegate d= new NewCarDelegate(DetailCar);

Car mycar=new Car();

Console.WriteLine(d(mycar));

Console.WriteLine(“Done invoking delegate”);

}

}

}

Notice that, this example makes use of a new namespace named

System.Threading. This namespace defines a type named Thread, which provides a

static method named CurrentThread(). If you obtain the hash code for the current

thread, you obtain a unique identifier for the currently executing thread.

Here, you print out the hash code of the current thread within Main(), and then

synchronously invoke the NewCarDelegate type. Once the flow of execution passes

into the DetailCar() helper function, you print out the hash code for the active

thread once again and put it to sleep for 10 seconds. Given this, you will not see the

final message of Main() print to the console until approximately 10 seconds after

the delegate’s invocation.

R.V.COLLEGE OF ENGINEERING Page 338

Page 339: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Invoking Methods Asynchronously

When the C# compiler processes the “delegate” keyword, you dynamically receive

two methods named BeginInvoke() and EndInvoke(). Thus, for the NewCarDelegate

type, you are provided with the following member:

public IAsyncResult BeginInvoke(Car carToDetail,

System.AsyncCallback callback, object state);

public string EndInvoke(IAsyncResult result);

Note that BeginInvoke() returns an IAsyncResult interface, while EndInvoke()

requires an IAsyncInvoke type as parameter.

In the simplest case, one is able to effectively ignore directly interacting with these

members. All you have to do is cache the returned IAsyncResult type in a local

variable in order to pass it to EndInvoke() when you are ready to obtain the result of

the method invocation.

1.48 Understanding (and using) Events

Delegates are fairly interesting constructs in that they enable two objects in

memory to engage in a two-way conversation. As you may agree, however, working

with delegates in the raw does require a good amount of boilerplate code (defining

the delegate, declaring necessary member variables, and creating custom

registration/un-registration methods). Because the ability for one object to call back

to another object is such a helpful construct, C# provides the event keyword to

lessen the burden of using delegates in the raw. When the compiler processes the

event keyword, you are automatically provided with registration and un-registration

R.V.COLLEGE OF ENGINEERING Page 339

Page 340: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

methods as well as any necessary member variable for your delegate types. In this

light, the event keyword is little more than syntactic sugar, which can be used to

save you some typing time.

Defining an event is a two-step process. First, you need to define a delegate that

contains the methods to be called when the event is fired. Next, you declare the

events (using the C# event keyword) in terms of the related delegate. In a nutshell,

defining a type that can send events entails the following pattern (shown in pseudo-

code):

public class SenderOfEvents

{

public delegate retval AssociatedDelegate(args);

public event AssociatedDelegate NameOfEvent;

...

}

The events of the Car type will take the same name as the previous delegates

(AboutToBlow and Exploded). The new delegate to which the events are associated

will be called CarEventHandler. Here are the initial updates to the Car type:

public class Car

{

// This delegate works in conjunction with the

// Car's events.

public delegate void CarEventHandler(string msg);

// This car can send these events.

R.V.COLLEGE OF ENGINEERING Page 340

Page 341: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

public event CarEventHandler Exploded;

public event CarEventHandler AboutToBlow;

...

}

Sending an event to the caller is as simple as specifying the event by name as well

as any required parameters as defined by the associated delegate. To ensure that

the caller has indeed registered with event, you will want to check the event against

a null value before invoking the delegate’s method set. These things being said,

here is the new iteration of the Car’s Accelerate() method:

public void Accelerate(int delta)

{

// If the car is dead, fire Exploded event.

if (carIsDead)

{

if (Exploded != null)

Exploded("Sorry, this car is dead...");

}

else

{

currSpeed += delta;

// Almost dead?

if (10 == maxSpeed – currSpeed && AboutToBlow != null)

{

AboutToBlow("Careful buddy! Gonna blow!");

}

R.V.COLLEGE OF ENGINEERING Page 341

Page 342: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

// Still OK!

if (currSpeed >= maxSpeed)

carIsDead = true;

else

Console.WriteLine("->CurrSpeed = {0}", currSpeed);

}

}

With this, you have configured the car to send two custom events without the need

to define custom registration functions. You will see the usage of this new

automobile in just a moment, but first, let’s check the event architecture in a bit

more detail.

1.49 Summary

In this unit, you have examined a number of ways in which multiple objects can

partake in a bidirectional conversation under .NET. First, you examined the use of

callback interfaces, which provide a way to have object B make calls on object A via

an interface reference. Next, you examined the C# delegate types which is used to

indirectly construct a class derived from System.MulticastDelegate. It is simply an

object that maintains a list of methods to call when told to do so. These invocations

may be made synchronously (using Invoke() method) or asynchronously (via

BeginInvoke() and EndInvoke() methods). Finally, you have seen event, which when

used in conjunction with a delegate type, can simplify the process of sending your

even notifications to awaiting callers.

1.50 Keywords

R.V.COLLEGE OF ENGINEERING Page 342

Page 343: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Function Pointer Callback Mechanism Sink Object Advice() and Unadvice() methods Callback functions Synchronous and asynchronous behavior of delegates Thread Thread object BeginInvoke() and EndInvoke() methods The keyword event

1.51 Exercises

7. Explain the concept of callback mechanism with an example.

8. Define sink objects.

9. Illustrate with an example, the usage of Advise() and UnAdvise() methods.

10.Define delegate with syntax. List out the information maintained by

delegates.

11.List out the members of System.MulticastDelegate along with the purpose.

12.Give an example for the implementation of delegates.

13.Explain the concept of synchronous and asynchronous delegate invocation.

14.Define thread.

15.What are events? Explain with an example.

Module 4

Unit 2

CONTENTS:

1.60 Objectives2.38 Introduction

R.V.COLLEGE OF ENGINEERING Page 343

Page 344: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

2.39 The advanced keywords of C#2.40 Building a Custom Indexer2.41 Overloading operators2.42 The Internal Representation of Overloading Operators2.43 Creating Custom Conversion Routines2.44 Defining Implicit Conversion Routines2.45 Summary2.46 Keywords2.47 Exercises

2.1 Objectives

At the end of this lesson, the students will understand the following tasks in detail:

The usage of keywords like checked, unchecked, unsafe, volatile etc.

Meaning of indexer and its usage

Operator overloading and the way they are represented by CIL

Explicit and implicit conversions.

2.37Introduction

This unit investigates advanced constructs of C#. You will learn how to

programmatically account for overflow/underflow conditions using

checked/unchecked keywords, how to create an unsafe code for directly

manipulating pointer types. Next, you learn how to construct and use an indexer

method, overloading operators (like +, - etc) and create custom conversion

functions (the C# equivalent to overloading the () operator under C++).

2.38 The Advanced Keywords of C#

Throughout our discussion till all these units, we have seen many C# keywords. In

addition to those, C# provides a set of keywords viz.

R.V.COLLEGE OF ENGINEERING Page 344

Page 345: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

checked/unchecked

unsafe/stackalloc/ fixed/volatile/sizeof

lock

Except the keyword lock, that is used in multithreading, we will discuss other

keywords here in detail.

The checked Keyword

As you know, each numerical data type has a fixed upper and lower limit (which

may be obtained programmatically using the MaxValue and MinValue properties).

Now, when you are performing arithmetic operations on a specific type, it is

possible that you may accidentally overflow the maximum storage of the type (i.e.,

assign a value that is greater than the maximum value) or underflow the minimum

storage of the type (i.e., assign a value that is less than the minimum value). These

two situations are together termed as overflow. Consider the following example for

illustration.

namespace CheckedUnchecked

{

class Program

{

static void Main(string[] args)

{

// max value of byte is 250

Console.WriteLine("Max value of byte is {0}.", byte.MaxValue);

Console.WriteLine("Min value of byte is {0}.", byte.MinValue);

byte b1 = 100;

byte b2 = 250;

byte sum = (byte)(b1 + b2);

R.V.COLLEGE OF ENGINEERING Page 345

Page 346: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Console.WriteLine("sum = {0}", sum);

}

}

}

The value of sum will be 94 but not 350. The reason is simple. Given that a

System.Byte can hold a value only between 0 and 255 (inclusive, for a grand total of

256 slots), sum now contains the overflow value (350 – 256 = 94). As you have just

seen, if you take no corrective course of action, overflow occurs without exception.

At times, this hidden overflow may cause no harm whatsoever in your project. Other

times, this loss of data is completely unacceptable.

To handle overflow or underflow conditions in your application, you have two

options. The first choice is to handle all overflow conditions manually. That, is you

can modify the statements like –

byte b1 = 100;

byte b2 = 250;

int sum = b1 + b2; // Store sum in integer to prevent overflow.

But, if the values of b1 and b2 are input from the keyboard, and if you forget to

declare sum as integer, then there will be an unexpected output. To avoid this

problem, C# provides the checked keyword. When you wrap a statement (or a block

of statements) within the scope of the checked keyword, the C# compiler emits

specific CIL instructions that test for overflow conditions that may result when

adding, multiplying, subtracting, or dividing two numerical data types. If an overflow

has occurred, the runtime will throw a System.OverflowException type. Observe the

changes in the following program:

R.V.COLLEGE OF ENGINEERING Page 346

Page 347: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

class Program

{

static void Main(string[] args)

{

// Overflow the max value of a System.Byte.

Console.WriteLine("Max value of byte is {0}.", byte.MaxValue);

byte b1 = 100;

byte b2 = 250;

try

{

byte sum = checked((byte)(b1 + b2));

Console.WriteLine("sum = {0}", sum);

}

catch(OverflowException e)

{ Console.WriteLine(e.Message); }

}

}

Here, you wrap the addition of b1 and b2 within the scope of the checked keyword.

If you wish to force overflow checking to occur over a block of code, the syntax

would be:

try

{

checked

R.V.COLLEGE OF ENGINEERING Page 347

Page 348: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

{

byte sum = (byte)(b1 + b2);

Console.WriteLine("sum = {0}", sum);

}

}

catch(OverflowException e)

{

Console.WriteLine(e.Message);

}

In either case, the code in question will be evaluated for possible overflow

conditions automatically, which will trigger an overflow exception if encountered.

The unchecked Keyword

Assume that, you have a block of code where silent overflow is acceptable. For this

purpose, C# provides the unchecked keyword to disable the throwing of

System.OverflowException on a case-by-case basis. The syntax is as same as that

of checked keyword. For example:

// Assuming /checked is enabled, this block will not trigger

// a runtime exception.

unchecked

{

byte sum = (byte)(b1 + b2);

Console.WriteLine("sum = {0}", sum);

}

R.V.COLLEGE OF ENGINEERING Page 348

Page 349: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

So, to summarize the C# checked and unchecked keywords, remember that the

default behavior of the .NET runtime is to ignore arithmetic overflow. When you

want to selectively handle discrete statements, make use of the checked keyword.

If you wish to trap overflow errors throughout your application, enable the /checked

flag. Finally, the unchecked keyword may be used if you have a block of code where

overflow is acceptable (and thus should not trigger a runtime exception).

Working with unsafe Code

We have three keywords that allow the C# programmer to bypass the CLR’s

memory management scheme in order to make use of C or C++ style pointers. For

this purpose, C# provides following operators:

C# Pointer-Centric

Operator

Meaning

* Used to create a pointer variable that represents a direct location in memory. Like C /C++, this same operator is used to represent pointer indirection.

& Used to obtain the address of a pointer

-> Used to access fields of a type that is represented by a pointer variable (the unsafe version of C# dot operator)

[ ] This allows you to index the slot pointed to by a pointer variable.

There will be only two situations where we need to use unsafe code (usage of

pointers:

R.V.COLLEGE OF ENGINEERING Page 349

Page 350: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

You are looking to optimize selected parts of your application by bypassing

the CLR. For example, you want to build a function that copies an array using

pointer arithmetic.

You are attempting to trigger the functionality of a C-based *.dll (such as the

Win32 API or a custom C-based *.dll) and need to create pointer variables to

call various methods.

The unsafe Keyword

When you wish to work with pointers in C#, you must specifically declare a block of

“unsafe” code using the unsafe keyword:

unsafe

{

// Work with pointer types here!

}

In addition to declaring a scope of unsafe code, you are able to build structures,

classes, type members, and parameters that are “unsafe.” Here are a few examples

to gnaw on:

// This entire structure is unsafe & can be used only in an unsafe context.

public unsafe struct Node

{

public int Value;

public Node* Left;

public Node* Right;

}

// This struct is safe, but the Node* members are not. Technically, you // may access 'Value' from outside an unsafe context, but not 'Left' and

// 'Right'.

public struct Node

R.V.COLLEGE OF ENGINEERING Page 350

Page 351: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

{

public int Value;

// These can be accessed only in an unsafe context!

public unsafe Node* Left;

public unsafe Node* Right;

}

Methods (static or instance level) may be marked as unsafe as well. For example,

assume that you know a given static method will make use of pointer logic. To

ensure that this method can be called only from an unsafe context, you could define

the method as follows:

unsafe public static void SomeUnsafeCode()

{

// Work with pointer types here!

}

This configuration demands that the caller invoke SomeUnsafeCode() as so:

static void Main(string[] args)

{

unsafe

{

SomeUnsafeCode();

}

}

R.V.COLLEGE OF ENGINEERING Page 351

Page 352: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Conversely, if you would rather not force the caller to wrap the invocation within an

unsafe context, you could remove the unsafe keyword from the SomeUnsafeCode()

method signature and opt for the following:

public static void SomeUnsafeCode()

{

unsafe

{

// Work with pointers here!

}

}

this would simplify the call to this:

static void Main(string[] args)

{

SomeUnsafeCode();

}

Working with the * and & Operators

Once you have established an unsafe context, you are then free to build pointers to

data types using the * operator and obtain the address of said pointer using the &

operator. Using C#, the * operator is applied to the underlying type only, not as a

prefix to each pointer variable name. For example, the following code declares two

variables, both of type int* (a pointer to an integer):

// Wrong syntax in C#

R.V.COLLEGE OF ENGINEERING Page 352

Page 353: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

int *p1, *p2;

// Correct syntax of C#.

int* p1, p2;

Consider the following example:

unsafe

{

int myInt;

// Define an int pointer, and assign it the address of myInt.

int* ptrToMyInt = &myInt;

// Assign value of myInt using pointer indirection.

*ptrToMyInt = 123;

// Print some stats.

Console.WriteLine("Value of myInt {0}", myInt);

Console.WriteLine("Address of myInt {0:X}", (int)&ptrToMyInt);

}

An Unsafe (and Safe) Swap Function

Declaring pointers to local variables simply to assign their value (as shown in the

previous example) is never required and not altogether useful. To illustrate a more

practical example of unsafe code, assume you wish to build a swap function using

pointer arithmetic:

unsafe public static void UnsafeSwap(int* i, int* j)

R.V.COLLEGE OF ENGINEERING Page 353

Page 354: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

{

int temp = *i;

*i = *j;

*j = temp;

}

But the same task can be achieved by a safe mode in C# as:

public static void SafeSwap(ref int i, ref int j)

{

int temp = i;

i = j;

j = temp;

}

Field Access via Pointers (The -> Operator)

Now assume that you have defined a Point structure and wish to declare a pointer

to a Point type. Like C/C++, when you wish to invoke methods or trigger fields of a

pointer type, you will need to make use of the pointer-field access operator ( ->).

This is the unsafe version of the standard (safe) dot operator (.). In fact, using the

pointer indirection operator (*), it is possible to dereference a pointer to (once

again) apply the dot operator notation. Check out the following:

struct Point

{

public int x;

public int y;

R.V.COLLEGE OF ENGINEERING Page 354

Page 355: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

public override string ToString()

{

return string.Format("({0}, {1})", x, y);

}

static void Main(string[] args)

{

unsafe // Access members via pointer.

{

Point point;

Point* p = &point;

p->x = 100;

p->y = 200;

Console.WriteLine(p->ToString());

}

unsafe // Access members via pointer indirection.

{

Point point;

Point* p = &point;

(*p).x = 100;

(*p).y = 200;

Console.WriteLine((*p).ToString());

}

}

R.V.COLLEGE OF ENGINEERING Page 355

Page 356: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

}

The stackalloc Keyword

In an unsafe context, you may need to declare a local variable that allocates

memory directly from the call stack (and is therefore not subject to .NET garbage

collection). To do so, C# provides the stackalloc keyword, which is the C#

equivalent to the _alloca() function of the C runtime library. Here is a simple

example:

unsafe

{

char* p = stackalloc char[256];

for (int k = 0; k < 256; k++)

p[k] = (char)k;

}

Pinning a Type via the fixed Keyword

As you saw in the previous example, allocating a chunk of memory within an unsafe

context may be facilitated via the stackalloc keyword. By the very nature of this

operation, the allocated memory is cleaned up as soon as the allocating method has

returned (as the memory is acquired from the stack). However, assume a more

complex example. During our examination of the -> operator, you created a value

type named Point. Like all value types, the allocated memory is popped off the

stack once the executing scope has terminated. For the sake of argument, assume

Point was instead defined as a reference type:

class Point // Now a class!

{

R.V.COLLEGE OF ENGINEERING Page 356

Page 357: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

public int x;

public int y;

public override string ToString()

{

return string.Format("({0}, {1})", x, y);

}

}

As you are well aware, if the caller declares a variable of type Point, the memory is

allocated on the garbage collected heap. Now the question is, what if an unsafe

context wishes to interact with this object (or any object on the heap)? Given that

garbage collection can occur at any moment, imagine the pain of accessing the

members of Point at the very point in time at which a sweep of the heap is under

way. Theoretically, it is possible that the unsafe context is attempting to interact

with a member that is no longer accessible or has been repositioned on the heap

after surviving a generational sweep (which is an obvious problem).

To lock a reference type variable in memory from an unsafe context, C# provides

the fixed keyword. The fixed statement sets a pointer to a managed type and “pins”

that variable during the execution of statement. Without fixed, pointers to managed

variables would be of little use, since garbage collection could relocate the variables

unpredictably. (In fact, the C# compiler will not allow you to set a pointer to a

managed variable except in a fixed statement.) Thus, if you create a Point type

(now redesigned as a class) and want to interact with its members, you must write

the following code (or receive a compiler error):

unsafe public static void Main()

{

Point pt = new Point();

pt.x = 5;

R.V.COLLEGE OF ENGINEERING Page 357

Page 358: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

pt.y = 6;

// pin pt in place so it will not be moved or GC-ed.

fixed (int* p = &pt.x)

{

// Use int* variable here!

}

// pt is now unpinned, and ready to be GC-ed.

Console.WriteLine ("Point is: {0}", pt);

}

In a nutshell, the fixed keyword allows you to build a statement that locks a

reference variable in memory, such that its address remains constant for the

duration of the statement. To be sure, any time you interact with a reference type

from within the context of unsafe code, pinning the reference is a must.

The volatile Keyword

When you define a volatile variable, you are performing the converse operation of

pinning a type in memory, in that you are telling the runtime that it is completely

fine to allow an outside agent to modify the item in question at any time. The

syntax would be –

volatile int x;

Basically, this keyword may be used to define a type filed that is accessed by

multiple threads without using the lock statement to serialize access.

R.V.COLLEGE OF ENGINEERING Page 358

Page 359: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

The sizeof Keyword

As in C/C++, the C# sizeof keyword is used to obtain the size in bytes for a value

type (never a reference type), and it may only be used within an unsafe context. As

you may imagine, this ability may prove helpful when you are interacting with

unmanaged C-based APIs. Its usage is straightforward:

unsafe

{

Console.WriteLine("The size of short is {0}.", sizeof(short));

Console.WriteLine("The size of int is {0}.", sizeof(int));

Console.WriteLine("The size of long is {0}.", sizeof(long));

}

As sizeof will evaluate the number of bytes for any System.ValueType-derived

entity, you are able to obtain the size of custom structures as well. Assume you

have defined the following struct:

struct MyValueType

{

public short s;

public int i;

public long l;

}

Console.WriteLine("The size of MyValueType is {0}.", sizeof(MyValueType));

2.39Building a Custom Indexer

As programmers, we are very familiar with the process of accessing discrete items

contained within a standard array using the index operator, for example:

R.V.COLLEGE OF ENGINEERING Page 359

Page 360: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

// Declare an array of integers.

int[ ] myInts = { 10, 9, 100, 432, 9874};

// Use the [ ] operator to access each element.

for(int j = 0; j < myInts.Length; j++)

Console.WriteLine("Index {0} = {1} ", j, myInts[j]);

The C# language provides the capability to build custom classes and structures that

may be indexed just like a standard array. The method that provides the capability

to access items in this manner is termed an indexer.

Consider the following example:

// Indexers allow you to access items in an arraylike fashion.

public class Program

{

static void Main(string[] args)

{

// Assume the Garage type has an indexer method.

Garage carLot = new Garage();

carLot[0] = new Car("FeeFee", 200);

carLot[1] = new Car("Clunker", 90);

carLot[2] = new Car("Zippy", 30);

// Now obtain and display each item using indexer.

//Assume PetName, CurrSpeed are defined properties of class

R.V.COLLEGE OF ENGINEERING Page 360

Page 361: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

for (int i = 0; i < 3; i++)

{

Console.WriteLine("Car number: {0}", i);

Console.WriteLine("Name: {0}", carLot[i].PetName);

Console.WriteLine("Max speed: {0}", carLot[i].CurrSpeed);

}

}

}

2.40Overloading Operators

Consider the following code snippet:

int a=20, b=30;

int c=a+b; //now c will be 50

string s1= “Hello”, s2= “World”;

string s3= s1+s2; //now s3 is “HelloWorld”

The + operator could able to perform addition of two numbers and concatenation of

two strings because, it has been overloaded internally. C# allows the programmer

to overload the intrinsic operators so as to work on objects of user-defined/custom

types (may be classes or structures etc.). This method is known as operator

overloading.

To illustrate the process of overloading binary operators, assume the following

simple Point structure:

R.V.COLLEGE OF ENGINEERING Page 361

Page 362: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

public struct Point

{

private int x, y;

public Point(int xPos, int yPos)

{

x = xPos;

y = yPos;

}

public override string ToString()

{

return string.Format("[{0}, {1}]", this.x, this.y);

}

// overloaded operator +

public static Point operator + (Point p1, Point p2)

{

return new Point(p1.x + p2.x, p1.y + p2.y);

}

// overloaded operator -

public static Point operator - (Point p1, Point p2)

{

return new Point(p1.x - p2.x, p1.y - p2.y);

}

R.V.COLLEGE OF ENGINEERING Page 362

Page 363: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

static void Main(string[] args)

{

Point ptOne = new Point(100, 100);

Point ptTwo = new Point(40, 40);

Console.WriteLine("ptOne = {0}", ptOne);

Console.WriteLine("ptTwo = {0}", ptTwo);

Point p1=ptOne + ptTwo;

Point p2=ptOne-ptTwo;

Console.WriteLine("p1: {0} ", p1.ToString());

Console.WriteLine("p2: {0} ", p2.ToString());

Console.ReadLine();

}

}

In the similar manner, one can overload all binary, unary and relational operators.

2.41Internal Representation of Overloaded Operators

Like any C# programming element, overloaded operators are represented using

specific CIL instructions. That is, any operator that you may overload equates to a

specially named method in terms of CIL. The following table lists few C# operator-

to-CIL mapping for the C# operators.

R.V.COLLEGE OF ENGINEERING Page 363

Page 364: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Intrinsic C# Operator

CIL

Representation

Intrinsic C# Operator

CIL Representation

-- op_Decrement() ! op_LogiaclNot()

++ op_Increment Binary + op_Addition()

Unary - op_UnaryNegation() Binary - op_Subtraction()

Unary + op_UnaryPlus() Binary * op_Multiply()

< op_LessThan() / op_Division()

2.42Creating Custom Conversion Routines

C# provides two keywords, explicit and implicit, that you can use to control how

your types respond during an attempted conversion. Assume you have the following

structure definitions:

public struct Rectangle

{

// Public for ease of use;

// however, feel free to encapsulate with properties.

public int Width, Height;

public void Draw()

{

R.V.COLLEGE OF ENGINEERING Page 364

Page 365: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Console.WriteLine("Drawing a rect.");

}

public override string ToString()

{

return string.Format("[Width = {0}; Height = {1}]", Width, Height);

}

}

public struct Square

{

public int Length;

public void Draw()

{

Console.WriteLine("Drawing a square.");

}

public override string ToString()

{

return string.Format("[Length = {0}]", Length);

}

// Rectangles can be explicitly converted into Squares.

public static explicit operator Square(Rectangle r)

{

Square s;

s.Length = r.Width;

return s;

}

R.V.COLLEGE OF ENGINEERING Page 365

Page 366: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

}

Notice that this iteration of the Rectangle type defines an explicit conversion

operator. Like the process of overloading an operator, conversion routines make use

of the C# operator keyword (in conjunction with the explicit or implicit keyword)

and must be defined as static. The incoming parameter is the entity you are

converting from, while the return value is the entity you are converting to:

public static explicit operator Square(Rectangle r)

{...}

In any case, the assumption is that a square (being a geometric pattern in which all

sides are of equal length) can be obtained from the width of a rectangle. Thus, you

are free to convert a Rectangle into a Square as so:

static void Main(string[] args)

{

Console.WriteLine("***** Fun with Custom Conversions *****\n");

// Create a 5 * 10 Rectangle.

Rectangle rect;

rect.Width = 10;

rect.Height = 5;

Console.WriteLine("rect = {0}", rect);

// Convert Rectangle to a 10 * 10 Square.

Square sq = (Square)rect;

Console.WriteLine("sq = {0}", sq);

R.V.COLLEGE OF ENGINEERING Page 366

Page 367: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Console.ReadLine();

}

While it may not be all that helpful to convert a Rectangle into a Square within the

same scope, assume you have a function that has been prototyped to take Square

types.

// This method requires a Square type.

private static void DrawSquare(Square sq)

{

sq.Draw();

}

Using your explicit conversion operation, you can safely pass in Square types for

processing:

static void Main(string[] args)

{

...

// Convert Rectangle to Square to invoke method.

DrawSquare((Square)rect);

}

2.43Defining Implicit Conversion Routines

Now we will discuss implicit conversion. Consider following situation:

static void Main(string[] args)

{

R.V.COLLEGE OF ENGINEERING Page 367

Page 368: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

...

// Attempt to make an implicit cast

Square s3;

s3.Length = 83;

Rectangle rect2 = s3;

}

As you might expect, this code will not compile, given that you have not provided

an implicit conversion routine for the Rectangle type. Now here is the catch: it is

illegal to define explicit and implicit conversion functions on the same type, if they

do not differ by their return type or parameter set. This might seem like a limitation;

however, the second catch is that when a type defines an implicit conversion

routine, it is legal for the caller to make use of the explicit cast syntax! To clear

things up, let’s add an implicit conversion routine to the Rectangle structure using

the C# implicit keyword (note that the following code assumes the width of the

resulting Rectangle is computed by multiplying the side of the Square by 2):

public struct Rectangle

{

...

public static implicit operator Rectangle(Square s)

{

Rectangle r;

r.Height = s.Length;

r.Width = s.Length * 2;

return r;

}

}

R.V.COLLEGE OF ENGINEERING Page 368

Page 369: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

With this update, you are now able to convert between types as follows:

static void Main(string[] args)

{

...

// Implicit cast OK!

Square s3;

s3.Length= 83;

Rectangle rect2 = s3;

Console.WriteLine("rect2 = {0}", rect2);

DrawSquare(s3);

// Explicit cast syntax still OK!

Square s4;

s4.Length = 3;

Rectangle rect3 = (Rectangle)s4;

Console.WriteLine("rect3 = {0}", rect3);

...

}

Again, be aware that it is permissible to define explicit and implicit conversion

routines for the same type as long as their signatures differ. Thus, you could update

the Square as follows:

public struct Square

{

...

// Can call as: Square sq2 = (Square)90; or as:

R.V.COLLEGE OF ENGINEERING Page 369

Page 370: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

// Square sq2 = 90;

public static implicit operator Square(int sideLength)

{

Square newSq;

newSq.Length = sideLength;

return newSq;

}

// Must call as: int side = (int)mySquare;

public static explicit operator int (Square s)

{

return s.Length;

}

}

2.44Summary

The purpose of this unit was to round out your understanding of the C#

programming Language. We began by examining a small set of lesser known

keywords (like sizeof, checked, unsafe etc.) and during the process came to learn

how to work with raw pointer types. Then we investigated various advanced type

construction techniques (indexer, overloading and custom conversion). As you have

seen, each of these constructs can be triggered from languages other than C#,

directly or indirectly.

2.45 Keywords

R.V.COLLEGE OF ENGINEERING Page 370

Page 371: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

The keywords like checked, unchecked, unsafe, stackalloc, fixed, volatile, sizeof and lock.

Overflow Pinning Indexer Operator overloading Explicit and Implicit conversions

2.46 Exercises

1. Explain the purpose of checked keyword with an example.2. What do you mean by unchecked? Illustrate with an example.3. List out the situations where we need unsafe code.4. Illustrate the usage of unsafe keyword with an example.5. How do you make use of * and & operators while handling pointers in C#?6. Write the functions for swapping two numbers in both safe mode and unsafe

mode.7. Explain the purpose of fixed keyword with an example.8. Define an indexer. Write a program to illustrate indexer.9. Write a program to depict the overloading of operators + and -.10.Explain the usage of the keyword explicit with an example.11.Write a code segment to illustrate the working of implicit conversion.

Module 4

Unit 3

CONTENTS:

1.61 Objectives3.2 Introduction

R.V.COLLEGE OF ENGINEERING Page 371

Page 372: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

3.3An Overview of .NET Assemblies

3.4Core Benefits of Assemblies

3.5Building a Single File Test Assembly

3.6Exploring the Manifest

3.7Building a Multifile Assembly

3.8Summary

3.10 Keywords

3.11 Exercises

3.1 Objectives

At the end of this lesson, the students will understand the following tasks in detail:

The concept of .NET assemblies

The basics of single file and multifile assemblies

The logical and physical views of assemblies

The benefits of using assemblies

A single file test assembly

The core of manifest and CIL instructions

An example for multifile assembly and its construction

3.34Introduction

Each of the applications developed in the previous modules are along the lines of

traditional stand-alone applications, given that all programming logic in contained

within a single *.exe. One major aspect of .NET is the notion of binary reuse. .NET

provides the ability to access types located in external binaries in a language-

independent manner. However, the .NET platform provides far greater language

integration. For example, the .NET platform supports cross-language inheritance

R.V.COLLEGE OF ENGINEERING Page 372

Page 373: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

(e.g., a Visual Basic .NET class deriving from a C# class). To understand how this is

achieved requires a deeper understanding of assemblies. In this unit, you

understand the logical and physical layout of an assembly.

3.35An Overview of .NET Assemblies

An assembly is a versioned, self-describing binary (*.dll or *.exe) containing some

collection of types (classes, interfaces, structures etc.) and optional resources

(images, string tables etc.). A .NET binary/assembly consists of five major elements:

A standard Windows file header (or Win32 header)

A CLR header that marks the file as a managed module

CIL code

Type metadata

The assembly manifest

The Win32 header is just above identical to that of an unmanaged binary and is

simply used to identify that the module is usable by the Windows operating system.

This header also identifies the type of application to be launched. The CLR header is

a block of information that all .NET files must support to be loaded by the CLR. This

header defines numerous flags that enable the runtime to understand the layout of

the managed file.

CIL code is a platform and CPU agnostic. At runtime, the internal CIL is compiled to

platform and CPU specific instructions. The type metadata completely describes

each type defined within the current assembly as well as the set of eternal types

referenced by this assembly. The manifest documents each module within the

assembly, establishes the version of the assembly and also documents any external

assemblies referenced by the current assembly. Given all these elements, a .NET

assembly is a completely self-describing entity.

R.V.COLLEGE OF ENGINEERING Page 373

Page 374: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Single File and Multifile Assemblies

An assembly can be composed of multiple modules. A module is a generic name for

a valid .NET file. Thus, an assembly can be viewed as a unit of versioning and

deployment (termed as logical DLL). In most situations, an assembly is composed of

a single module. In this case, there is a one-to-one correspondence between the

(logical) assembly and the underlying (physical) binary as shown in the following

diagram.

When you create an assembly that is composed of multiple files, you gain a more

efficient way to download content. For example, assume you have a remote client

tat is referencing a multifile assembly composed of three modules, one of which is

automatically installed with the client. If the client references another of the

remote modules, the .NET runtime will download the file on demand. If each

module is large in size, then multifile assembly will help to more extent.

R.V.COLLEGE OF ENGINEERING Page 374

Manifest

Type Metadata

CIL Code

(Optional) Resources

A Single File Assembly

Test.dll

Page 375: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Note that, multifile assemblies are not literally linked together into a new (larger)

file. Rather, multifile assemblies are logically related by information contained in the

corresponding manifest. Multifile assemblies contain a single manifest that may be

placed in a sand-alone file, but is more typically bundled directly into the primary

module. The following diagram depicts a multifile assembly.

R.V.COLLEGE OF ENGINEERING Page 375

Manifest (References other

related files)

Type Metadata

CIL Code

Type Metadata

CIL Code

Type Metadata

CIL Code

CompanyLogo.bmp

Test.dll

Bar.netmodule

Qaaz.netmodule

A Multifile Assembly

Page 376: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Two Views of an Assembly: Physical and Logical

As you begin to work with .NET binaries, it can be helpful to regard an assembly

(both single file and multifile) as having two conceptual views. When you build an

assembly, you are interested in the physical view. In this case, the assembly can be

realized as some number of files that contain your custom types and resources as

shown below:

As an assembly consumer, you are typically interested in a logical view of the

assembly as shown below. In this case, you can understand an assembly as a

versioned collection of public types that you can use in your current application.

R.V.COLLEGE OF ENGINEERING Page 376

Test.dll

Bar.netmodule Manifest

Resource Files

Physical View of an Assembly

Classes

Interfaces Resources

Enumerations

Logical View of an Assembly

Delegates

Structures

Page 377: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

3.36Core Benefits of Assemblies

The assembly format of files has some benefits as explained below:

Assemblies Promote Code Reuse: As you have been building your console

applications over the previous chapters, it may have seemed that all of the

applications’ functionality was contained within the executable assembly you

were constructing. In reality, your applications were leveraging numerous

types contained within the always accessible .NET code library, mscorlib.dll

(recall that the C# compiler references mscorlib.dll automatically), as well as

System.Windows.Forms.dll. As you may know, a code library (also termed a

class library) is a *.dll that contains types intended to be used by external

applications. When you are creating executable assemblies, you will no doubt

be leveraging numerous system-supplied and custom code libraries as you

create the application at hand. Do be aware, however, that a code library

need not take a *.dll file extension. It is perfectly possible for an executable

assembly to make use of types defined within an external executable file. In

this light, a referenced *.exe can also be considered a “code library.”

Regardless of how a code library is packaged, the .NET platform allows you to

reuse types in a language-independent manner. For example, you could

create a code library in C# and reuse that library in any other .NET

programming language. It is possible to not only allocate types across

languages, but derive from them as well. A base class defined in C# could be

extended by a class authored in Visual Basic .NET. Interfaces defined in

Pascal .NET can be implemented by structures defined in C#, and so forth.

The point is that when you begin to break apart a single monolithic

executable into numerous .NET assemblies, you achieve a language-neutral

form of code reuse.

Assemblies Establish a Type Boundary: In the module 2, you learned

about the formalities behind .NET namespaces. Recall that a type’s fully

R.V.COLLEGE OF ENGINEERING Page 377

Page 378: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

qualified name is composed by prefixing the type’s namespace (e.g., System)

to its name (e.g., Console). Strictly speaking however, the assembly in which

a type resides further establishes a type’s identity. For example, if you have

two uniquely named assemblies (say, MyCars.dll and YourCars.dll) that both

define a namespace (CarLibrary) containing a class named SportsCar, they

are considered unique types in the .NET universe.

Assemblies Are Versionable Units: .NET assemblies are assigned a four-

part numerical version number of the form <major>.<minor>.

<build>.<revision> (if you do not explicitly provide a version number using

the [AssemblyVersion] attribute, the assembly is automatically assigned a

version of 0.0.0.0). This number, in conjunction with an optional public key

value, allows multiple versions of the same assembly to coexist in harmony

on a single machine. Formally speaking, assemblies that provide public key

information are termed strongly named. Using a strong name, the CLR is able

to ensure that the correct version of an assembly is loaded on behalf of the

calling client.

Assemblies Are Self-Describing: Assemblies are regarded as self-

describing in part because they record every external assembly it must have

access to in order to function correctly. Thus, if your assembly requires

System.Windows. Forms.dll and System.Drawing.dll, they will be documented

in the assembly’s manifest. Recall that a manifest is a blob of metadata that

describes the assembly itself (name, version, external assemblies, etc.). In

addition to manifest data, an assembly contains metadata that describes the

composition (member names, implemented interfaces, base classes,

constructors and so forth) of every contained type. Given that an assembly is

documented in such vivid detail, the CLR does not consult the Win32 system

registry to resolve its location (quite the radical departure from Microsoft’s

legacy COM programming model). The CLR makes use of an entirely new

scheme to resolve the location of external code libraries.

R.V.COLLEGE OF ENGINEERING Page 378

Page 379: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Assemblies Are Configurable: Assemblies can be deployed as “private” or

“shared.” Private assemblies reside in the same directory (or possibly a

subdirectory) as the client application making use of them. Shared

assemblies, on the other hand, are libraries intended to be consumed by

numerous applications on a single machine and are deployed to a specific

directory termed the Global Assembly Cache (GAC). Regardless of how you

deploy your assemblies, you are free to author XML-based configuration files.

Using these configuration files, the CLR can be instructed to “probe” for

assemblies under a specific location, load a specific version of a referenced

assembly for a particular client, or consult an arbitrary directory on your local

machine, your network location, or a web-based URL.

Assemblies Define a Security Context: An assembly may also contain

security details. Under the .NET platform, security measures are scoped at

the assembly level. For example, if AssemblyA wishes to use a class

contained within AssemblyB, then AssemblyB is the entity that chooses to

provide access (or not). The security constrains defined by an assembly are

explicitly listed within its manifest. While a treatment of .NET security

measures is outside the mission of this text, simply be aware that access to

an assembly’s contents is verified using assembly metadata

.

Assemblies Enable Side-by-Side Execution: Perhaps the biggest

advantage of the .NET assembly is the ability to install and load multiple

versions of the same assembly on a single machine. In this way, clients are

isolated from other incompatible versions of the same assembly. Further

more, it is possible to control which version of a (shared) assembly should be

loaded using application configuration files. These files are little more than a

simple text file describing (via XML syntax) the version, and specific location,

of the assembly to be loaded on behalf of the calling application.

R.V.COLLEGE OF ENGINEERING Page 379

Page 380: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

3.37Building a Single File Test Assembly

Now, you have a better understanding of the benefits provided by .NET assemblies,

let’s build a minimal and complete code library using C#. Physically, this will be a

single file assembly named CarLibrary. Logically, this binary will contain a handful of

public types for consumption by other .NET binaries.

The design of our automobile library begins with an abstract base class named Car

that defines a number of protected data members exposed through custom

properties. This class has a single abstract method named TurboBoost() and makes

use of a single enumeration (EngineState). Here is the initial definition of the

CarLibrary namespace.

using System;

namespace CarLibrary

{

// Represents the state of the engine.

public enum EngineState

{

engineAlive, engineDead

}

// The abstract base class in the hierarchy.

public abstract class Car

{

protected string petName;

R.V.COLLEGE OF ENGINEERING Page 380

Page 381: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

protected short currSpeed;

protected short maxSpeed;

protected EngineState egnState = EngineState.engineAlive;

public abstract void TurboBoost();

public Car(){}

public Car(string name, short max, short curr)

{

petName = name;

maxSpeed = max;

currSpeed = curr;

}

public string PetName

{

get { return petName; }

set { petName = value; }

}

public short CurrSpeed

{

get { return currSpeed; }

set { currSpeed = value; }

}

public short MaxSpeed

{

R.V.COLLEGE OF ENGINEERING Page 381

Page 382: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

get { return maxSpeed; }

}

public EngineState EngineState

{

get { return egnState; }

}

}

}

Now assume that you have two direct descendents of the Car type named MiniVan

and SportsCar. Each overrides the abstract TurboBoost() method in an appropriate

manner.

using System;

using System.Windows.Forms; //needed for MessageBox definition

namespace CarLibrary

{

public class SportsCar : Car

{

public SportsCar(){ }

public SportsCar(string name, short max, short curr): base (name,

max, curr){ }

public override void TurboBoost()

R.V.COLLEGE OF ENGINEERING Page 382

Page 383: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

{

MessageBox.Show("Ramming speed!", "Faster is better...");

}

}

public class MiniVan : Car

{

public MiniVan(){ }

public MiniVan(string name, short max, short curr): base (name,

max, curr){ }

public override void TurboBoost()

{

// Minivans have poor turbo capabilities!

egnState = EngineState.engineDead;

MessageBox.Show("Time to call AAA", "Your car is dead");

}

}

}

3.38Exploring the Manifest

After creating a single file code library, the next task will be understanding

assembly construction. Recall that every assembly contains an associated manifest.

The manifest contains bits of metadata that specify the name and version of the

R.V.COLLEGE OF ENGINEERING Page 383

Page 384: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

assembly, as well as a listing of all internal and external modules that compose the

assembly as a whole.

Additionally, a manifest may contain cultural information (used for

internationalization), a corresponding strong name (required by shared assemblies)

and optional resource information. The following table describes some of the key

bits of functionality lurking within an assembly manifest.

Manifest-Centric

Information

Meaning

Assembly Name A text string specifying the assembly’s name.

Version Number A major and minor version number, and a revision and build number.

Strong name information

In part, the strong name of an assembly consists of a public key maintained by the publisher of the assembly.

List of all modules in the assembly

A hash of each module contained in the assembly (in the case of a single file assembly, there will only be a single module listing).

Information on referenced assemblies

A list of other assemblies that are statistically referenced by the assembly.

R.V.COLLEGE OF ENGINEERING Page 384

Page 385: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

.NET aware compilers (such as csc.exe) automatically create a manifest at compile

time. CIL instructions are created within the assembly manifest. The following table

lists the core CIL tokens created for a manifest.

Manifest Tag Meaning

.assembly Marks the assembly declaration, indicating that the file is an assembly.

.file Marks additional files in a multifile assembly.

.class extern Classes exported by the assembly but declared in another module (only used with a multifile assembly).

.manifestres Indicates the manifest resources, if any.

.module Module declaration, indicating that the file is a module (i.e. a .NET binary with no assembly level manifest) and not the primary assembly.

.assembly extern The assembly reference indicates another assembly containing items referenced by this module.

.publickey Contains the actual bytes of the public key.

.publickeytoken Contains a token of the actual public key.

R.V.COLLEGE OF ENGINEERING Page 385

Page 386: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

3.39Building a Multifile Assembly

Now that we have explored the internals of a single file assembly, let’s turn our

attention to the process of building a multifile assembly. Recall that a multifile

assembly will contain a particular *.dll or *.exe file that contains the assembly

manifest (often termed as the primary module). Additionally, multifile assemblies

contain any number of *.netmodule files that are loaded on demand when

referenced by an external client. Do be aware that the use of *.netmodule is simply

a naming convention. If you wish, your auxiliary modules could simply take a *.dll

file extension.

The Visual Studio.NET does not support a project workspace type that allows you to

build stand-alone *.netmodule files. Therefore, you need to drop down to the level

of the raw csc.exe compiler and specify the correct flags manually.

To keep things simple, let’s build some rather basic types contained within a

multifile assembly named AirVehicles. The primary airvehicles.dll module will

contain CIL and metadata for a single class type named Helicopter. The related

manifest (also contained in airvehicles.dll) catalogues and additional *.netmodule

file named ufos.netmodule, which contains another class type named UFO.

Although both class types are physically contained in separate binaries, you will

group them into a unified namespace named AirVehicles. Finally, both classes are

created using C#.

To begin, open notepad.exe and create a trivial class definition name UFO within a

file named ufo.cs:

R.V.COLLEGE OF ENGINEERING Page 386

Page 387: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

using System;

namespace AirVehicles

{

public class UFO

{

public void AbductHuman()

{

Console.WriteLine(“Resistance is futile”);

}

}

}

To compile this class into a .NET module, open a command prompt and issue the

following command to the C# compiler:

csc.exe /t:module ufo.cs

If you now look in the folder containing the ufo.cs file, you should see a new file

named ufo.netmodule. Next, create a new file named helicopter.cs:

using System;

namespace AirVehicles

{

public class Helicopter

{

R.V.COLLEGE OF ENGINEERING Page 387

Page 388: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

public void TakeOff()

{

Console.WriteLine(“Helicopter taking off!!”);

}

}

}

Given that AirVehicles.dll is the primary module of this multifile assembly, you will

need to specify the /t:library flag. However, as you also want to encode the

ufo.netmodule binary into the assembly manifest, you must also specify the

/addmodule flag. The following command does the trick:

csc /t:library /addmodule:ufo.netmodule /out:airvehicles.dll helicopter.cs

At this point, your directory should contain the primary arivehicles.dll module as

well as the secondary ufo.netmodule binaries.

3.40Summary

This chapter drilled into the details behind the innocent-looking .NET dlls and exes

located on your development machine. You began the journey by examining the

core concepts of the assembly: CLR headers, metadata, manifests and CIL. As

illustrated, .NET supports the notion of cross-language inheritance.

You have seen the concept and working of single file assembly and multifile

assemblies. Also, you have understood the core of manifest and CIL instructions.

R.V.COLLEGE OF ENGINEERING Page 388

Page 389: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

3.41 Keywords

File Header

Module

CIL (Common Intermediate Language)

Metadata

Manifest

Physical View of Assembly

Logical View of Assembly

Code Library /Class Library

Language-Neutral Form

Fully Qualified Name

Public Key Value

Strongly named assembly

Global Assembly Cache (GAC)

Primary module

3.42 Exercises

1. What are the major elements of an assembly? Explain.

2. With a neat diagram, explain the concepts of single file and multifile

assemblies.

3. What do you mean by logical and physical views of an assembly? Explain.

4. Bring out the core benefits of assemblies.

5. Write a C# code to illustrate single file assembly and explain the same.

6. List out the information contained by the assembly manifest.

7. List out the core CIL tokens created for a manifest.

8. How do you build a multifile assembly? Explain.

R.V.COLLEGE OF ENGINEERING Page 389

Page 390: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Module 4

Unit 4

CONTENTS:

1.62 Objectives4.2 Introduction

4.3Understanding Private Assemblies

4.4 Probing for Private Assemblies (The Basics)

4.5 Private Assemblies and XML Configuration Files

4.6 Probing for Private Assemblies (The Details)

4.7Understanding Shared Assembly

4.8Understanding Strong Names

4.9Building a Shared Assembly

4.10 Understanding Delayed Signing

4.11 Installing/Removing Shared Assembly

4.12 Using a Shared Assembly

4.13 Summary

4.14 Keywords

4.15 Exercises

7.1 Objectives

R.V.COLLEGE OF ENGINEERING Page 390

Page 391: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

At the end of this lesson, the students will understand:

The meaning of private assemblies and XML configuration

The concept of probing

Shared assemblies and its detailed study

Strong Names and signing

4.34Introduction

In the previous unit, you have understood the concept of assemblies. Once you

understand the logical and physical layout of an assembly, you learn the distinction

between private and shared assemblies as well as single file and multifile

assemblies. Here, you examine exactly how .NET runtime resolves the location of an

assembly and come to understand the role of the Global Assembly Cache (GAC) and

application configuration files (*.config). As you will see, *.config files may be used

by a client application to interact with the assembly binding process.

4.35Understanding Private Assemblies

Formally speaking, every assembly is deployed as private or shared. Each variable

has the same underlying structure (i.e., some number of modules and an associated

manifest). Furthermore, each flavor of assembly provides the same kind of services

(access to some number of public types). The real differences between a private

and shared assembly boil down to naming conventions, versioning policies and

deployment issues.

Private assemblies are a collection of modules that is only used by the application

with which it has been deployed. For example, CarLibrary.dll seen in previous unit

is a private assembly. When you create and deploy a private assembly, the

R.V.COLLEGE OF ENGINEERING Page 391

Page 392: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

assumption is that the collection of types is only used by the owning application and

not shared with other applications on the system.

Private assemblies are required to be located within the same directory as the client

application (termed the application directory) or a subdirectory thereof. For

example, when you set a reference to the CarLibrary.dll assembly, the Visual Studio

.NET IDE responded by making a full copy of the assembly that was placed in your

project’s application directory. This is the default behavior, as private assemblies

are assumed to be the deployment option of choice.

The resolution and loading of the private CarLibrary.dll happens by virtue of the fact

that the assembly is placed in the application directory. Uninstalling (or replicating)

an application that makes exclusive use of private assemblies is a no-brainer:

simply delete (or copy) the application folder. Unlike with COM applications, you do

not need to worry about dozens of orphaned registry settings. More important, you

do not need to worry that the removal of private assemblies will break any other

applications on the machine.

The full identity of a private assembly consists of the friendly name and numerical

version, both of which are recorded in the assembly manifest. The friendly name

simply is the name of the module that contains the assembly’s manifest minus the

file extension. For example, if you examine the manifest of the CarLibrary.dll

assembly, you find the following (your version will no doubt differ):

.assembly CarLibrary

{

...

.ver 1:0:454:30104

R.V.COLLEGE OF ENGINEERING Page 392

Page 393: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

}

Given the isolated nature of a private assembly, it should make sense that the CLR

does not bother to make use of the version number when resolving its location. The

assumption is that private assemblies do not need to have any elaborate version

checking, as the client application is the only entity that “knows” of its existence.

Given this, it is (very) possible for a single machine to have multiple copies of the

same private assembly in various application directories.

4.36Probing for Private Assemblies(The Basics)

The .NET runtime resolves the location of a private assembly using a technique

termed probing, which is much less invasive than it sounds. Probing is the process

of mapping an external assembly reference (i.e. [.assembly extern]) to the correct

corresponding binary file. For example, when the runtime reads the following line

from the CSharpCarClient manifest:

.assembly extern CarLibrary

{……}

a search is made in the application directory for a file named CarLibrary.dll. If a

*.dll binary cannot be located, an attempt is made to locate an *.exe version. If

neither if these files can be located in the application directory, the runtime throws

an exception. However, XML configuration files (*.config) can be used to instruct

the runtime to probe in other locations beyond the application directory.

4.37Private Assemblies and XML Configuration Files

R.V.COLLEGE OF ENGINEERING Page 393

Page 394: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

While it is possible to deploy a .NET application by simply copying all required

assemblies to a single folder on the user’s hard drive, you will most likely wish to

define a number of subdirectories to group related content. For example, assume

you have an application directory named C:\MyApp that contains

CSharpCarClient.exe. Under this folder might be a subfolder named MyLibraries that

contains CarLibrary.dll.

Regardless of the intended relationship between these two directories, the CLR will

not probe the MyLibraries subdirectory unless you supply a configuration file.

Configuration files contain various XML elements that allow you to influence the

probing process. By “law,” configuration files must have the same name as the

launching application and take a *.config file extension, and they must be deployed

in the client’s application directory. Thus, if you wish to create a configuration file

for CSharpCarClient.exe, it must be named CSharpCarClient.exe.config.

To illustrate the process, create a new directory on your C drive named MyApp

using Windows Explorer. Next, copy CSharpCarClient.exe and CarLibrary.dll to this

new folder, and run the program by double-clicking the executable. Your program

should run successfully at this point (remember, the assemblies are not

registered!). Next, create a new subdirectory under C:\MyApp named MyLibraries,

and move CarLibrary.dll to this location.

Try to run your client program again. Because the CLR could not locate “CarLibrary”

directly within the application directory, you are presented with a rather nasty

unhandled FileNotFound exception. To rectify the situation, create a new

configuration file named CSharpCarClient.exe.config and save it in the same folder

containing the CSharpCarClient.exe application, which in this example would be C:\

MyApp. Open this file and enter the following content exactly as shown (be aware

that XML is case sensitive!):

R.V.COLLEGE OF ENGINEERING Page 394

Page 395: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

<configuration>

<runtime>

<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">

<probing privatePath="MyLibraries"/>

</assemblyBinding>

</runtime>

</configuration>

.NET *.config files always open with a root element named <configuration>. The

nested <runtime> element may specify an <assemblyBinding> element, which

nests a further element named <probing>. The privatePath attribute is the key

point in this example, as it is used to specify the subdirectories relative to the

application directory where the CLR should probe.

Do note that the <probing> element does not specify which assembly is located

under a given subdirectory. In other words, you cannot say, “CarLibrary is located

under the MyLibraries subdirectory, but MathUtils is located under Bin

subdirectory.” The <probing> element simply instructs the CLR to investigate all

specified subdirectories for the requested assembly until the first match is

encountered.

Multiple subdirectories can be assigned to the privatePath attribute using a

semicolon-delimited list. You have no need to do so at this time, but here is an

example that informs the CLR to consult the MyLibraries and MyLibraries\Tests

client subdirectories:

<probing privatePath="MyLibraries; MyLibraries\Tests"/>

R.V.COLLEGE OF ENGINEERING Page 395

Page 396: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Once you’ve finished creating CSharpCarClient.exe.config, run the client by double-

clicking the executable in Windows Explorer. You should find that

CSharpCarClient.exe executes without a hitch (if this is not the case, double-check it

for typos).

Next, for testing purposes, change the name of your configuration file (in one way

or another) and attempt to run the program once again. The client application

should now fail. Remember that *.config files must be prefixed with the same name

as the related client application. By way of a final test, open your configuration file

for editing and capitalize any of the XML elements. Once the file is saved, your

client should fail to run once again (as XML is case sensitive).

4.38Probing for Private Assemblies (The Details)

To wrap up our discussion of private assemblies, let’s formalize the specific steps

involved in binding to a private assembly at runtime. First, a request to load an

assembly may be either explicit or implicit. An implicit load request occurs

whenever the manifest makes a direct reference to some external assembly. The

external references are marked with [.assembly extern] token:

//an implicit load request

.assembly extern CarLibrary

{

…….

}

R.V.COLLEGE OF ENGINEERING Page 396

Page 397: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

An explicit load request occurs programmatically using the Load() or LoadFrom()

method of the System.Reflection.Assembly class type, typically for the purposes of

late binding and dynamic invocation of type members. The Load() method allows

you to specify the name, version, public key token and culture information

syntactically. You can see an example of an explicit load request in the following

code:

// An explicit load request.

Assembly asm = Assembly.Load("CarLibrary");

Collectively, the name, version, public key token and cultural information is termed

as assembly reference (or simply AsmRef). The entity in charge of locating the

correct assembly based on an AsmRef is termed the assembly resolver, which is a

facility of the CLR. If the resolver determines the AsmRef refers to a private

assembly (i.e. no public key token is specified), the following steps are followed:

1. First, the assembly resolver attempts to locate the assembly in the client’s

application directory (looking for a *.dll file on the first pass, followed by

an *.exe file).

2. If the AsmRef cannot be resolved in looking in the application directory,

the assembly resolver will attempt to locate a configuration file in the

application directory. If a configuration file exists, the runtime will

attempt to locate the private assembly using the <probing> element.

3. If the assembly cannot be found within the application directory (or a

specified subdirectory), the search stops here and a FileNotFound

exception is raised.

Again, the location of a private assembly is fairly simple to resolve.

R.V.COLLEGE OF ENGINEERING Page 397

Page 398: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

4.39Understanding Shared Assemblies

Now that you understand how to deploy and configure a private assembly, you can

begin to examine the role of a shared assembly. Like a private assembly, a shared

assembly is a collection of types and (optional) resources. The most obvious

difference between shared and private assemblies is the fact that a single copy of a

shared assembly can be used by several applications on a single machine.

Consider all the applications created in this text that required you to set a reference

to System. Windows.Forms.dll. If you were to look in the application directory of

each of these clients, you would not find a private copy of this .NET assembly. The

reason is that System.Windows.Forms.dll has been deployed as a shared assembly.

Clearly, if you need to create a machine-wide class library, this is the way to go. As

suggested in the previous paragraph, a shared assembly is not deployed within the

same directory as the application making use of it. Rather, shared assemblies are

installed into the Global Assembly Cache (GAC). The GAC is located under a

subdirectory of your Windows directory named Assembly (e.g., C:\Windows\

Assembly).

4.40Understanding Strong Names

Before you can deploy an assembly to the GAC, you must assign it a strong name,

which is used to uniquely identify the publisher of a given .NET binary. Understand

that a “publisher” could be an individual programmer, a department within a given

company, or an entire company at large.

In some ways, a strong name is the modern day .NET equivalent of the COM

globally unique identifier (GUID) identification scheme. If you have a COM

R.V.COLLEGE OF ENGINEERING Page 398

Page 399: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

background, you may recall that AppIDs are GUIDs that identify a particular COM

application. Unlike COM GUID values (which are nothing more than 128-bit

numbers), strong names are based (in part) on two cryptographically related keys

(termed the public key and the private key), which are much more unique and

resistant to tampering than a simple GUID.

Formally, a strong name is composed of a set of related data, much of which is

specified using assembly-level attributes:

The friendly name of the assembly (which you recall is the name of the

assembly minus the file extension)

The version number of the assembly (assigned using the [AssemblyVersion]

attribute)

The public key value (assigned using the [AssemblyKeyFile] attribute)

An optional culture identity value for localization purposes (assigned using

the [AssemblyCulture] attribute)

An embedded digital signature created using a hash of the assembly’s

contents and the private key value

To provide a strong name for an assembly, your first step is to generate

public/private key data using the .NET Framework 2.0 SDK’s sn.exe utility (which

you’ll do momentarily). The sn.exe utility responds by generating a file (typically

ending with the *.snk [Strong Name Key] file extension) that contains data for two

distinct but mathematically related keys, the “public” key and the “private” key.

Once the C# compiler is made aware of the location for your *.snk file, it will record

the full public key value in the assembly manifest using the .publickey token at the

time of compilation.

The C# compiler will also generate a hash code based on the contents of the entire

assembly (CIL code, metadata, and so forth). A hash code is a numerical value that

is unique for a fixed input. Thus, if you modify any aspect of a .NET assembly (even

R.V.COLLEGE OF ENGINEERING Page 399

Page 400: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

a single character in a string literal) the compiler yields a unique hash code. This

hash code is combined with the private key data within the *.snk file to yield a

digital signature embedded within the assembly’s CLR header data. The process of

strongly naming an assembly is illustrated in the following figure:

Understand that the actual private key data is not listed anywhere within the

manifest, but is used only to digitally sign the contents of the assembly (in

conjunction with the generated hash code). Again, the whole idea of making use of

public/private key cryptography is to ensure that no two companies, departments,

or individuals have the same identity in the .NET universe. In any case, once the

process of assigning a strong name is complete, the assembly may be installed into

the GAC.

R.V.COLLEGE OF ENGINEERING Page 400

Manifest with Public Key

Type Metadata

CIL

Digital Signature

CarLibrary.dll

Assembly Hash Code

Digital Signature

Private

Key Data+ =

Page 401: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

4.41Building a Shared Assembly

To illustrate the process of assigning a strong name to an assembly, let us consider

an example. Assume you have created a new C# Class Library named

SharedAssembly, which contains the following class definition:

public class VWMiniVan

{

private bool x=false;

public VWMiniVan()

{

MessageBox.Show(“Using Version 2.0”, “Shared Car”);

}

public void PlayTune()

{

MessageBox.Show(“What a long drive …”);

}

public bool Busted

{

get { return x;}

set { x=value;}

}

}

R.V.COLLEGE OF ENGINEERING Page 401

Page 402: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

To generate the key file, you need to make use of the sn.exe (strong name) utility.

Although this tool has numerous command line options, now, you have to use “-k”

flag, which instructs the tools to generate a new *.snk file that contains the

public/private key information.

The next step is to inform the C# compiler exactly where the *.snk file is located to

record the public key in the assembly manifest. When you create a new C# project

workspace, you will notice that one of your initial project files is named

“AssemblyInfo.cs”. This file contains a number of attributes that describe the

assembly itself. One attribute that may appear within this file is named

AssemblyKeyFile. Simply update the initial empty value with a string specifying the

location of your *.snk file, for example:

[assembly: AssemblyKeyFile(@ “C:\MyKey\myKey.snk”)]

Given that the version of a shared assembly is of prime importance, let us specify a

fixed numerical value. In the same AssemblyInfo.cs file, you will find another

attribute named AssemblyVersion. Initially the value is set of “1.0.*”:

[assembly: AssemblyVersion (“1.0.*”)]

Every new C# projects begins life versioned at 1.0.*. Recall that a .NET version

number is composed of the four parts (<major>.<minor>.<build>.<revision>).

Until you say otherwise, VS.NET automatically increments the build and revision

numbers as part of each compilation. To enforce a fixed value for the assembly’s

build version, simply update accordingly:

[assembly: AssemblyVersion(“1.0.0.0”)]

R.V.COLLEGE OF ENGINEERING Page 402

Page 403: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Using these two assembly-level attributes, the C# compiler now merges the

necessary information into the corresponding manifest to establish you strong

name, which can be seen using ildasm.exe.

4.42 Understanding Delayed Signing

When you are building your own custom .NET assemblies, you are able to assign a

strong name using your own personal *.snk file. However, given the sensitive nature

of a public/private key file, don’t be too surprised if your company/department

refuses to give you access to the master *.snk file. This is an obvious problem,

given that we (as developers) will often need to install an assembly into the GAC for

testing purposes. To allow this sort of testing (while not distributing the true *.snk

file), you are able to make use of delayed signing. We have no need to do so for the

current CarLibrary.dll; however, here is an overview of the process. Delayed signing

begins by the trusted individual holding the *.snk file extracting the public key value

from the public/private *.snk file using the -p command-line flag of sn.exe, to

produce a new file that only contains the public key value:

sn -p myKey.snk testPublicKey.snk

At this point, the testPublicKey.snk file can be distributed to individual developers

for the creation and testing of strongly named assemblies. To inform the C#

compiler that the assembly in question is making use of delayed signing, the

developer must make sure to set the value of the AssemblyDelaySign attribute to

true in addition to specifying the pseudo-key file as the parameter to the

AssemblyKeyFile attribute. Here are the relevant updates to the project’s

AssemblyInfo.cs file:

[assembly: AssemblyDelaySign(true)]

R.V.COLLEGE OF ENGINEERING Page 403

Page 404: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

[assembly: AssemblyKeyFile(@"C:\MyKey\testPublicKey.snk)]

Once an assembly has enabled delayed signing, the next step is to disable the

signature verification process that happens automatically when an assembly is

deployed to the GAC. To do so, specify the -vr flag (using sn.exe) to skip the

verification process on the current machine:

sn.exe -vr MyAssembly.dll

Once all testing has been performed, the assembly in question can be shipped to

the trusted individual who holds the “true” public/private key file to resign the

binary to provide the correct digital signature. Again, sn.exe provides the necessary

behavior, this time using the -r flag:

sn.exe -r MyAssembly.dll C:\MyKey\myKey.snk

To enable the signature verification process, the final step is to apply the -vu flag:

sn.exe -vu MyAssembly.dll

Understand, of course, that if you (or your company) only build assemblies intended

for internal use, you may never need to bother with the process of delayed signing.

However, if you are in the business of building .NET assemblies that may be

purchased by external parties, the ability to delay signing keep things safe and sane

for all involved.

4.43 Installing/Removing Shared Assembly

R.V.COLLEGE OF ENGINEERING Page 404

Page 405: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

The final step is to install SharedAssembly.dll into the GAC. The simplest way to

install a shared assembly into the GAC is to drag-and-drop the *.dll onto the active

window using the Windows Explorer. Also, the .NET SDK provides a command line

utility named gacutil.exe (the /i flag is used to install the binary.

Once an assembly has been installed into the GAC, you may right-click a given

assembly icon to pull up a property page fro the binary, as well as delete the item

from the GAC altogether (the GUI equivalent of supplying the /u flag when using

gacutil.exe).

4.44 Using a Shared Assembly

Now let us make use of our shared assembly. Create a new C# Console Application

named SharedAssemblyClient. Like any external assembly, you will need to set a

reference to the SharedAssembly binary using the Add Reference dialog.

Understand, however that you do not navigate to the GAC directory when

referencing shared binaries. The GAC is a runtime entity that is not intended to be

accessed directly during the development cycle. Rather, navigate to the \Debug

folder of the SharedAssembly project using the Browse button. At this point,

exercise you VWMiniVan as:

public class SharedAsmClient

{

public static void Main(strin[] args)

{

VWMiniVan v= new VWMiniVan();

v.PlayTune();

}

R.V.COLLEGE OF ENGINEERING Page 405

Page 406: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

}

Once you have run your application, check out the client’s application directory

using the Windows Explorer. Recall, than when you reference a private assembly,

the IDE automatically creates a local copy of the assembly for use by the client

application. However, when you reference an assembly that contains a public key

value, VS.NET will not generate a local copy, given the assumption that assemblies

supporting a public key are typically shared and hence placed in the GAC.

4.45 Summary

As you have seen, assemblies may be private or shared, given that private

assemblies are the default. When you wish to configure a shared assembly, you are

making an explicit choice and need to generate a corresponding strong name. Both

private and shared assemblies can be configured declaratively using a client side

*.config file or alternatively, a publisher policy *.dll. This unit wrapped up by quickly

examining a set of related assembly-centric details: the machine.config file,

the .NET configuration untility to simplify the process of building XML configuration

files etc.

4.46 Keywords

Global Assembly Cache (GAC) Private Assembly Application Directory Friendly Name Probing Configuration Files Explicit and implicit load request Assembly Reference Assembly Resolver Public Key Token Shared Assembly

R.V.COLLEGE OF ENGINEERING Page 406

Page 407: 10mca53-TEAII-DotNET (1)

TOPICS IN ENTEPRISE ARCHITECTURE –II, 5TH MCA (10MCA53)

Strong names Globally Unique Identifier (GUID) Cryptographically related keys (public key and private key) Digital Signature Hash Code Delayed Signing

4.47 Exercises

1. Explain the concept of private assemblies.

2. Define probing.

3. How do you make use of XML configuration files to handle private assemblies?

Explain with a code segment.

4. Define implicit load request with syntax.

5. When an explicit load request occurs? Explain with the syntax.

6. List out the steps taken by resolver to identify a public key token.

7. Explain the concept of shared assemblies.

8. What do you mean by strong names? Explain.

9. List out the entities that formulate a strong name.

10.Explain the process of strongly naming an assembly with a diagram.

11.How do you build a shared assembly? Explain with a code segment.

12.What is the need for delayed signing? Explain.

13.With the help of attributes used, explain the procedure for delayed signing.

14.Briefly explain the procedure for using a shared assembly with an example.

R.V.COLLEGE OF ENGINEERING Page 407