Enterprise Architecture - II

Bandari Ravikiran October 28, 2009

2

For this material contact ravikiran1312@sify.com

Ravikiran

Contents
1 Philosophy of .NET 1.1 Life Before .NET . . . . . . . . . . . . . . . . . . . . . 1.2 .NET Features . . . . . . . . . . . . . . . . . . . . . . 1.3 Building blocks of .NET . . . . . . . . . . . . . . . . . 1.3.1 Common Lanugage Runtime (CLR) . . . . . . 1.3.2 Common Type System(CTS) . . . . . . . . . . 1.3.3 Cross Language Specification (CLS) . . . . . . 1.4 Base Class Library[BCL) . . . . . . . . . . . . . . . . 1.5 C# Language . . . . . . . . . . . . . . . . . . . . . . . 1.5.1 C# Language Features . . . . . . . . . . . . . . 1.6 Overview of .NET Assemblies . . . . . . . . . . . . . . 1.7 Common Intermediate Language (CIL) . . . . . . . . . 1.7.1 Advantages of CIL . . . . . . . . . . . . . . . . 1.7.2 Compiling CIL to platform specific Instructions 1.8 Common Type System . . . . . . . . . . . . . . . . . . 1.8.1 Built - In Data Types . . . . . . . . . . . . . . 1.9 Common Language Specification . . . . . . . . . . . . 1.10 Common Language Runtime(CLR) . . . . . . . . . . . 1.10.1 Features of CLR . . . . . . . . . . . . . . . . . 1.11 Namespaces in .NET . . . . . . . . . . . . . . . . . . . 1.11.1 Accessing a Namespace . . . . . . . . . . . . . 1.12 Deploying .NET Framework . . . . . . . . . . . . . . . 7 7 11 12 12 12 12 12 13 13 13 15 15 16 16 17 18 18 19 20 20 21 23 23 23 23 24 25 25 26 26 28 29 29 29 30

. . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . .

2 Building C# Applications 2.1 C# Command Line Compiler . . . . . . . . . . . . . . . . . 2.1.1 Configuring the C# Command-Line Compiler . . . . 2.1.2 Configuring Additional .NET Command-Line Tools 2.2 Building C# Applications using csc.exe . . . . . . . . . . . 2.2.1 Referencing External Assemblies . . . . . . . . . . . 2.3 csc.exe Response Files . . . . . . . . . . . . . . . . . . . . . 2.3.1 The Default Response File(csc.rsp) . . . . . . . . . . 2.4 Generating Bug Reports . . . . . . . . . . . . . . . . . . . . 2.5 Remaining C# Compiler Options . . . . . . . . . . . . . . . 2.6 The Command Line Debugger (cordbg.exe) . . . . . . . . . 2.6.1 Debugging at Command Line . . . . . . . . . . . . . 2.7 Using Visual Studio - .NET IDE . . . . . . . . . . . . . . . 2.7.1 The VS.NET Start Page . . . . . . . . . . . . . . . . 3

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

4

CONTENTS

2.7.2 Creating VS.NET Project Solution . . . Building VS.NET Test Application . . . . . . . 2.8.1 Examining the solution explorer window 2.8.2 Examining Class View . . . . . . . . . . 2.9 VS.NET Solution Properties . . . . . . . . . . . 2.9.1 Properties Window . . . . . . . . . . . . 2.10 Other Key Aspects of VS.NET IDE . . . . . . 2.10.1 Server Explorer Window . . . . . . . . . 2.10.2 XML-Related editing tools . . . . . . . 2.10.3 Object Browser Utility . . . . . . . . . . 2.10.4 Database Manipulation in Visual Studio 2.11 C# language’s preprocessor directives . . . . . 2.12 System Environment Class . . . . . . . . . . . 2.8 3 C# Language Fundamentals 3.1 Anatomy of C# Class . . . . . . . . 3.1.1 Attributes . . . . . . . . . . . . 3.1.2 Modifiers . . . . . . . . . . . . 3.1.3 Main Method . . . . . . . . . . . 3.2 Constructors . . . . . . . . . . . . . . . 3.2.1 Types of Constructors . . . . . . 3.3 System.Console . . . . . . . . . . . . . . 3.3.1 Basic Input and Output with the 3.3.2 Formatting Console output . . . 3.3.3 Formatting Numbers . . . . . . . 3.3.4 Custom Number Formatting . . 3.3.5 Date Formatting . . . . . . . . . 3.3.6 Custom Date Formatting . . . . 3.4 Default values for variables . . . . . . . 3.5 Variable Scope . . . . . . . . . . . . . . 3.6 Member Variable Initialization . . . . . 3.7 Value Types and Reference Types . . . 3.7.1 Value Types . . . . . . . . . . . . 3.7.2 Reference Types . . . . . . . . . 3.8 Boxing and Unboxing . . . . . . . . . . 3.8.1 Boxing . . . . . . . . . . . . . . . 3.8.2 UnBoxing . . . . . . . . . . . . . 3.9 System.Object . . . . . . . . . . . . . . 3.10 Constant Data . . . . . . . . . . . . . . 3.10.1 const modifier . . . . . . . . . . . 3.10.2 By using readonly modifer . . . . 3.11 Iteration Constructs in C# . . . . . . . 3.11.1 while loop . . . . . . . . . . . . . 3.11.2 do-while loops . . . . . . . . . . 3.11.3 for loops . . . . . . . . . . . . . . 3.11.4 foreach loop . . . . . . . . . . . . 3.12 Flow Control statements in C# . . . . . 3.12.1 Jump Statements . . . . . . . . . 3.12.2 Selection Statements . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

30 32 32 33 34 35 35 35 36 36 37 37 40 43 43 43 43 44 45 46 48 48 49 50 50 51 51 52 52 53 53 53 54 55 55 56 56 59 59 60 60 60 61 61 62 62 62 64

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Console Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Ravikiran

CONTENTS

5

3.13 3.14 3.15 3.16

C# Operators . . . . . . . . . . . . . . . . . . . . Defining Custom Class Methods . . . . . . . . . Static Methods . . . . . . . . . . . . . . . . . . . Method Parameter Modifiers in C# . . . . . . . 3.16.1 Value parameters . . . . . . . . . . . . . . 3.16.2 Reference parameters . . . . . . . . . . . 3.16.3 Output Parameters . . . . . . . . . . . . . 3.16.4 Parameter arrays . . . . . . . . . . . . . . 3.17 Arrays in C# . . . . . . . . . . . . . . . . . . . . 3.17.1 Array Bounds Checking . . . . . . . . . . 3.17.2 Multi Dimensional Arrays . . . . . . . . . 3.17.3 System.Array class . . . . . . . . . . . . . 3.18 String Manipulation in C# . . . . . . . . . . . . 3.18.1 String Manipulation Methods . . . . . . . 3.18.2 System.Text.StringBuilder Class . . . . . 3.18.3 Escape Characters and Verbatim Strings . 3.19 Enumerations . . . . . . . . . . . . . . . . . . . . 3.19.1 System.Enum class . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . .

65 66 66 67 68 68 69 70 70 71 71 71 73 73 75 75 76 77 81 81 82 83 83 84 84 85 88 89 90 90 92 93 95 96 96 97 99 99 99 100 101 101 102 103 105 105 106

4 Object Oriented Programming using C# 4.1 Definition of C# class . . . . . . . . . . . . . . . . . . . . . . . . 4.1.1 Constructors . . . . . . . . . . . . . . . . . . . . . . . . . 4.2 Self Reference in C# . . . . . . . . . . . . . . . . . . . . . . . . . 4.2.1 Forwarding Constructor Calls using ”this” . . . . . . . . . 4.3 Default Public Interface . . . . . . . . . . . . . . . . . . . . . . . 4.4 Pillars of OOP . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.4.1 Encapsulation . . . . . . . . . . . . . . . . . . . . . . . . 4.5 Inheritance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.5.1 Classical Inheritance : . . . . . . . . . . . . . . . . . . . . 4.5.2 Containment / Delegation model (”Has-A” Relationship) 4.5.3 ”base”- keyword . . . . . . . . . . . . . . . . . . . . . . . 4.5.4 Preventing Inheritance : Sealed classes . . . . . . . . . . . 4.6 Ploymorphism . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.7 Abstract Classes & Abstract Methods . . . . . . . . . . . . . . . 4.8 Type Casting in C# . . . . . . . . . . . . . . . . . . . . . . . . . 4.8.1 ”is” - Operator . . . . . . . . . . . . . . . . . . . . . . . . 4.8.2 ”as” - operator . . . . . . . . . . . . . . . . . . . . . . . . 5 Exceptions and Object Lifetime 5.1 Introduction to Errors, Bugs, and Exceptions . . . . . . . 5.2 The Role of .NET Exception Handling . . . . . . . . . . . 5.2.1 The Elements of .NET Exception Handling . . . . 5.3 The System.Exception Base Class . . . . . . . . . . . . . . 5.3.1 Members of System.Exception Class . . . . . . . . 5.4 Throwing a Generic Exception . . . . . . . . . . . . . . . 5.5 Catcing Exceptions . . . . . . . . . . . . . . . . . . . . . . 5.6 CLR System-Level Exceptions (System.SystemException) 5.7 Custom Application-Level Exceptions . . . . . . . . . . . 5.7.1 Creating Custom Exceptions . . . . . . . . . . . . Ravikiran

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

6

CONTENTS

5.8 5.9 5.10 5.11 5.12 5.13 5.14 5.15 5.16 5.17 5.18

Handling Multiple Exceptions . . . . . . . . . . . . . . The Finally Block . . . . . . . . . . . . . . . . . . . . Last chance of Exception . . . . . . . . . . . . . . . . Identifing Application and System Exceptions . . . . . Debugging Unhandled Exceptions using Visual Studio Understanding Object Life Time . . . . . . . . . . . . The CIL of ”new” . . . . . . . . . . . . . . . . . . . . Garbage Collection Algorithm . . . . . . . . . . . . . . Finializing a Type . . . . . . . . . . . . . . . . . . . . The Finalization Process . . . . . . . . . . . . . . . . . Building an Ad Hoc Destruction Method . . . . . . . . 5.18.1 The IDisposable Interface . . . . . . . . . . . . 5.18.2 Reusing the C# ”using” Keyword . . . . . . . 5.19 Garbage Collection Optimizations . . . . . . . . . . . 5.20 The System.GC Type . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

107 108 109 109 110 111 112 112 114 114 115 115 116 116 117 119 120 121 121 125 126 126 128 129 130 133 135 136 138 138 138 139 139 139 140 140

6 Interfaces and Collections 6.1 Implementing Interfaces . . . . . . . . . . . . . . . . . . . . . 6.2 Contrasting Interfaces to Abstract Base Classes . . . . . . . . 6.3 Invoking Interface Members at Object Level . . . . . . . . . . 6.4 Explicit Interface Implementation . . . . . . . . . . . . . . . . 6.4.1 The Advantages of Explicit Interface Implementations 6.5 Building Interface Hierarchies . . . . . . . . . . . . . . . . . . 6.6 IConvertible Interface . . . . . . . . . . . . . . . . . . . . . . 6.6.1 The IConvertible.ToXXXX() Members . . . . . . . . . 6.7 Building Custom Enumerator . . . . . . . . . . . . . . . . . 6.8 Building Cloneable objects . . . . . . . . . . . . . . . . . . . . 6.9 Building Comparable Objects (IComparable) . . . . . . . . . 6.9.1 Specifying Multiple Sort Order . . . . . . . . . . . . . 6.10 Exploring the System.Collections Namespace . . . . . . . . . 6.10.1 The Interfaces of System.Collections . . . . . . . . . . 6.10.2 The Role of ICollection . . . . . . . . . . . . . . . . . 6.10.3 The Role of IDictonary . . . . . . . . . . . . . . . . . 6.10.4 The Role of IDictionaryEnumerator . . . . . . . . . . 6.10.5 The Role of IHashCodeProvider . . . . . . . . . . . . 6.10.6 The Role of IList . . . . . . . . . . . . . . . . . . . . . 6.10.7 The Class Types of System.Collections . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

Ravikiran

Chapter 1

Philosophy of .NET
1.1 Life Before .NET

C Language The main philosophy of C Language is ”Programmers know what to do”, but it does not help or assist or warn you about anything, unless there is some syntactical error like some type mismatch, or some macro redefinition, or some array’s index goes out of bound, etc... Main drawbacks of C Language are 1. Concept of Pointers is the powerful feature of C Language. But, they are highly insecure and makes it vulnerable. 2. The concept of re usability is achieved only through functions, so it makes it more complex for coding big projects as we have to write everything from scratch and hence lot of time is wasted. 3. C developers have to concentrate on memory management as there is no automatic memory management. 4. Since C is structured language, it lacks all the benefits of object oriented programming concepts like Abstraction, Encapsulation, Inheritance and Polymorphism Besides all these, C is a powerful language, thats why, a majority of Operating Systems are built using C. C++ Language C++ was designed at AT & T Bell Labs by Bjarne Stroustrup in the early 80s. The main features of C++ are • Stronger typechecking 7

8

CHAPTER 1. PHILOSOPHY OF .NET

• Support for data abstraction • Support for object-oriented programming • Support for generic programming Apart from these advantages, C++ has following drawbacks • It is not truly object oriented • It is not suitable for developing web technologies • It does not support versioning i.e. creation and management of multiple versions of a software. All versions have the same general function but they are improved, upgraded or customized. New versions of software modules can work with existing applications • It is not type-safe. It means the following – C++ arrays are unbound. – Compile time errors are not generated when uninitialized arrays are used • C++ still support pointers which will leads to major errors in programs and also it makes C++ programs highly insecure Visual Basic 6.0 Like many things, VB’s greatest strengths are also its greatest weaknesses. The following are some of the advantages of VB 1. VB was originally designed as a programming language for non-programmers. To that end, the syntax was designed to read more like natural language sentences than instructions to a computer. 2. As VB does not support pointers, it does limit what we can do with VB 3. In VB, there is no need to specify the type of a variable, or even declaring the variable itself. This provide an advantage of using a variable without having to worry about, or even knowing about the data type or size of the variable. Drawbacks of VB are 1. VB is not fully object oriented 2. Developing multi-threading applications using VB is a bit complex as we have to call the low level WIN32 API calls 3. We have to distribute a runtime with all of our applications (or install it to the computer before you use the application). This adds to a larger download (not all versions of windows have the VB6 runtime and even less have the .Net framework). The minimum distribution package is greater than 1 floppy. This is because the VB 6.0 run-time must be included. Ravikiran

1.1. LIFE BEFORE .NET

9

4. As there is no need to declare the data type of variables prior to its usage, there will be more chances to get runtime errors 5. Every time you create a new form or code file, you must remember to specify the directory where you want it stored. There is no default setting to specify that new code for a specific project should default to a specific directory. JAVA / J2EE Java is one of the most popular programming language, because of its following features.. 1. It is Platform Independent 2. It contains large number of predefined packages that contain various type definitions. 3. Java programmers can build pure Java applications complete with database connectivity, messaging support, web-enabled front ends, and a richer user interface 4. Java eliminates pointers which is major concern in C and C++ 5. Allows Concurrent control in an application 6. Garbage collection is one of the powerful feature of JAVA which automatically cleans the memory. Like any programming language, Java is not without drawbacks. Here are some of the drawbacks of JAVA... 1. Java applets are not supported by all the browsers and they need separate plug-in to be installed 2. Java developers have less control over on garbage collection to free objects 3. Primary goal of Java is to make Java as a single programming language for every need. So Java offers a little chance for language integration. COM Component Object Model, abbreviated as COM, is Microsofts framework for developing and supporting component objects. It enables interprocess communication and dynamic object creation. COM is an architecture that says ”If you build your classes in accordance with the rules of COM, you end up with a block of reusable binary code”. The COM model has come into widespread use since its introduction by Microsoft and it is an integral part of many Microsoft applications and technologies, including Internet Explorer and the Office suite of applications. Unlike traditional software development, which required each application to be built from scratch, COM allows developers to create complex applications using a series of small software objects. Ravikiran

10

CHAPTER 1. PHILOSOPHY OF .NET

COM lets developers make portions of their applications using components. For example, a component might be a tax calculation engine or the business rules for a price list. This approach speeds up the development process by allowing several teams to work on separate parts at the same time. Developers can also reuse components from one project to the next, and they can easily swap out or update a particular component without affecting other portions of the application. 1. The primary advantage of the Component Object Model is that it is founded on the objectoriented principles 2. It has given rise to the development of popular technologies like COM+ and the .NET framework. COM+ provides the users with support for distributed transactions. The .NET framework has taken over the COM platform and is largely being used for software development 3. COM technology is perhaps the most suitable means of developing and deploying desktop applications 4. COM can best be described as an infrastructure that allows building speedy, and extensible component-based software Drawbacks of COM are 1. Writing COM classes is very complex 2. We cannot create a new COM class with existing COM class Windows DNA Architecture DNA stands for Distributed interNet Application Architecture. Windows DNA is essentially a ’blueprint’ that enables corporate developers and independent software vendors (ISVs) to design and build distributed business applications using technologies that are inherent to the Windows platform. ”It consists of a conceptual model and a series of guidelines to help developers make the right choices when creating new software applications.” Applications based on Windows DNA will be deployed primarily by businesses, from small companies to large enterprise organizations. Consumers are likely to use many of the applications built to take advantage of Windows DNA, such as electronic commerce Web sites and on-line banking applications. Central to Windows DNA is the concept that applications should be logically separated into partitions, called tiers. The three tiers of Windows DNA are: 1. Presentation or User Interface 2. Business logic 3. Data Storage Ravikiran

1.2. .NET FEATURES

11

Drawbacks of DNA Architecture 1. DNA is quite complex because of the fact that Windows DNA requires the use of numerous technologies and languages (ASP, HTML, XML, JavaScript, VBScript, and COM(+), as well as a data access API such as ADO). 2. Each technology is different from other technology in their syntax and also in semantics. So when they are combined in DNA, it may results in highly confused mishmash of technologies.

1.2

.NET Solution

The main features of .NET are • .NET is multi-lingual With the .NET platform we can use several languages, such as C++, JScript, VB.NET, C# etc... All these languages are combined via an intermediate binary code, which is independent of hardware and operating systems. This intermediate language called Microsoft Intermediate Language (MSIL) is then executed in the Common Language Runtime(CLR) which is the execution environment of .NET applications • .NET Applications are portable Applications compiled as intermediate code are presented as Portable Executables (PEs). These PEs can be implemented over a vast range of hardware and software architectures: Intel PCs with windows 9x, Windows NT4, Windows 2000 or 64 bit windows versions, PocketPC and other operating systems. • All Languages must agree with a common agreement For a language to be eligible for the range of languages supported by the .NET platform, it must provide a set of possibilities and constructions listed in the agreement called Common Language Specification (CLS). To add a language to .NET, all that is required is for it to meet the requirements of the CLS, and a compiler to convert that language into MSIL. • Managed Codes All Code in .NET is managed code because the runtime provides services that include automatic memory management, debugging support, enhanced security. Earlier, the developers had to explicitly manage the memory in languages like C++. • Complete and total language integration: Unlike COM, .NET supports cross-language inheritance, cross-language exception handling, and cross-language debugging. • Base class library: .NET framework provides a class library that offers a consistent object model used by all .NET-aware languages. • Interoperability: All languages supported by the .NET framework support a common set of programming classes as their base class library. This means that the developers will not have trouble while interoperating between languages since all of them support the Ravikiran

12

CHAPTER 1. PHILOSOPHY OF .NET

same set of APIs and also have the same data types as specified by the Common Type Specification (CTS)

1.3

Introducing the Building Blocks of the .NET Platform (the CLR, CTS, and CLS)

The three building blocks of .NET platform are • Common Language Runtime(CLR) • Common Type System (CTS) • Cross Language Specification (CLS)

1.3.1

Common Lanugage Runtime (CLR)

The .NET framework provides a run-time environment called the Common Language Runtime, which manages the execution of code and provides services that make the development process easier. CLR makes it easy to design components and applications whose objects interact across languages. Objects written in different languages can communicate with each other and their behaviors can be tightly integrated.

1.3.2

Common Type System(CTS)

With so many languages to run in same runtime environment, it becomes a necessity that they all follow some guidelines. In .NET framework, CTS describes the types supported by the runtime and specifies how those types can interact with each other. The types in the runtime’s type system include classes, interfaces and value types.

1.3.3

Cross Language Specification (CLS)

.NET provides support for language interoperability. However, it doesnt mean every program written in a language can be used by another language. To enable a program to be used with other languages, it must be created by following a set of rules called Cross Language Specifications (CLS). The runtime provides cross language integration through a new Common Type System. the Common Type System defines a standard set of types that can represent the types supported by most modern programming languages. It also provides rules for creating new types, if required.

1.4

The Role of the Base Class Libraries

The Base Class Library (BCL) is a standard library available to all languages using the .NET Framework. .NET includes the BCL in order to encapsulate a large number of common functions, such as file reading and writing, graphic rendering, database interaction, and XML document Ravikiran

1.5. C# LANGUAGE

13

manipulation, which makes the programmer’s job easier. The BCL is sometimes incorrectly referred to as the Framework Class Library (FCL), which is a superset including the Microsoft.* namespaces

1.5

C# Language

Microsoft has developed a new programming language, C# (pronounced ”see sharp”), specifically for this new platform. C# is a programming language that looks very similar (but not identical) to the syntax of Java. C# is primarily derived from the C, C++, and Java programming languages with some features of Microsoft’s Visual Basic in the mix.

1.5.1

C# Language Features

c# language offers the following features (many of which are shared by other .NET-aware programming languages): • No pointers required c# programs typically have no need for direct pointer manipulation • Unsafe operations such as direct memory manipulation are not allowed. • Since it‘s on .NET, it inherits the features of automatic memory management and garbage collection. • C# has been based according to the current trend and is very powerful and simple for building interoperable, scalable, robust applications. • As of C# 2005, the ability to build generic types and generic members using a syntax very similar to C++ templates. • The C++-like ability to overload operators for a custom type, without the complexity • Arrays are zero base indexed and are bound checked. • Overflow of types can be checked As C# comes along with .NET platform, it can only produce code that can execute within the .NET runtime. Officially speaking, the term used to describe the code targeting the .NET runtime is managed code. The binary unit that contains the managed code is termed an assembly and the code that cannot be directly hosted by the .NET runtime is termed as unmanaged code.

1.6

Overview of .NET Assemblies

An assembly is the primary building block of a .NET application and can take the form of a dynamic link library (DLL) or executable file (EXE). An assembly is a collection of functionality that is built, versioned, and deployed as a single implementation unit. Ravikiran

14

CHAPTER 1. PHILOSOPHY OF .NET

In the Microsoft .NET framework, an assembly is a partially compiled code library for use in deployment, versioning and security. The .NET assembly is the standard for components developed with the Microsoft.NET. Dot NET assemblies may or may not be executable, i.e., they might exist as the executable (.exe) file or dynamic link library (.dll) file. All the .NET assemblies contain the definition of types, versioning information for the type and meta-data. .NET assemblies do not contain platform specific instructions.

Figure 1.1: All .NET-aware compilers emit IL instructions and metadata. When a *.dll or *.exehas been created using a .NET-aware compiler, the resulting module is bundled into an assembly. An assembly contains CIL (Common Intermediate Language) code, which is conceptually similar to Java bytecode and it is not compiled to platform specific instructions. In addition to CIL instructions , assemblies also contain metadata that describes the various characteristics of every ”type” described with in the binary assembly. Finally, in addition to CIL and type metadata, assemblies themselves are also described using metadata, which is officially termed as 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. A .NET assembly may contain the following elements: 1. Assembly Manifest :An assembly manifest is metadata inside an assembly that describes everything there is to know about the assembly and its contents. The manifest contains: (a) Strong Name - The assembly’s name, version, culture, optional processor architecture, and public key (for shared assemblies) (b) File Contents - Name and hash of all files in the assembly (c) Type List - Types defined in the assembly, including public types that are exported from the assembly (d) Resource List - Icons, images, text strings and other resources contained in the assembly (e) Dependencies - Compile-time dependencies on other assemblies Ravikiran

1.7. COMMON INTERMEDIATE LANGUAGE (CIL)

15

(f) Security - Permissions required for the assembly to run properly 2. Source Code :Compiled into Microsoft intermediate language (MSIL) 3. Type Metadata : Defines all types, their properties and methods, and most importantly, public types exported from this assembly 4. Resources :Icons, images, text strings and other resources Single-File and Multi file Assemblies The .NET platform supports two broad types of assemblies Single file assemblies: 1. A single *.dll or *.exe file which contains the CIL code, metadata, manifest and optional resources in one binary package. 2. This is the simplest type of assemblies. It contains the type information and implementation as well as the assembly’s manifest into a single physical file. 3. Class Libraries, Windows Forms / WPF applications, Console applications and Windows Services are all examples of single file assemblies. Multi-file assemblies: An assembly can consist of one or more files called modules. Exactly one of these modules contains the assembly manifest. Note that the files in a multi-file assembly can reside in separate locations and are linked together with the assembly manifest. Multi-file assemblies are rare, and Visual Studio doesn’t directly support their creation. The most common reason for multi-file assemblies is when a single assembly combines code from multiple programming languages.

1.7

Common Intermediate Language (CIL)

.NET language compilers do not emit native platform code. Rather, they emit platformindependent instructions called the Common Intermediate Language (CIL). CIL is an objectoriented assembly language, and is entirely stack-based. It is executed by a virtual machine. CIL is a language that sits above any particular platform-specific instruction set. Regardless of which .NET-aware language we choose, the associated compiler emits CIL instructions.

1.7.1

Advantages of CIL

1. Language Integration :The main benefit of CIL is Language Integration. As all the .NET aware compilers produce nearly identical CIL Instructions, the program written in one language can be interact with other language. ( Note that both the languages should be .NET aware languages) Ravikiran

16

CHAPTER 1. PHILOSOPHY OF .NET

2. Platform Independence As CIL doesn’t emit any platform specific code, CIL is an platform independent code. Besides, there is an international standard for the C# language, and a large subset of the .NET platformand implementations already exist for many nonWindows operating systems

1.7.2

Compiling CIL to platform specific Instructions

As CIL instructions are not platform specific (not machine code), they have to be converted into machine language. In .NET, this work is carried out by Just - in - time Compiler (JIT Compiler) The .NET runtime environment leverages a JIT compiler for each CPU targeting the runtime, each optimized for the underlying platform CIL is just-in-time compiled to the target platform at runtime. A block of code (method) is just-in-time complied when it is first called by a client. JIT compilation provides environmentspecific optimization, runtime type safety, and assembly verification. To accomplish this, the JIT compiler examines the assembly metadata for any illegal accesses and handles violations appropriately. 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 when the PrintDocument() is called, there is no need to recompile the CIL.

1.8

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 ( A set may be either class or structure or interface or enumeration or delegate) As .Net Framework is language independent and support over 20 different programming languages, many programmers will write data types in their own programming language. For example, an integer variable in C# is written as int, whereas in Visual Basic it is written as integer. Therefore in .Net Framework you have single class called System.Int32 to interpret these variables. Similarly, for the ArrayList data type .Net Framework has a common type called System.Collections.ArrayList. In .Net Framework, System.Object is the common base type from where all the other types are derived. This system is called Common Type System. The types in .NET Framework are the base on which .NET applications, components, and controls are built. Common Type System in .Net Framework defines how data types are going to be declared and managed in runtime. The Common Type System performs the following functions: 1. Automatically adapts itself in a framework that enables integration of multiple languages, type safety, and high performance code execution. Ravikiran

1.8. COMMON TYPE SYSTEM

17

2. Provides an object-oriented model that supports the complete implementation of many programming languages. 3. Defines rules that languages must follow, which helps ensure that objects written in different languages can interact with each other. There are two general types of categories in .Net Framework that Common Type System support. They are value types and reference types. Value types contain data and are user-defined or builtin. they are placed in a stack or in order in a structure. Reference types store a reference of the values memory address. They are allocated in a heap structure. You can determine the type of a reference by the values of self-describing types. Reference types can be categorized into self-describing types, pointer types, or interface types. There are five different types defined in .NET framework 1. CTS Class Type : Every .NET-aware language supports, the notion of a class type, which is the cornerstone of object-oriented programming (OOP). A class may be composed of any number of members (such as properties, methods, and events) and data points (fields). 2. CTS Structure Type : The concept of a structure is also formalized under the CTS. A structure can be thought of as a lightweight class type having value-based semantics 3. 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. 4. CTS Enumeration Types :Enumerations are a handy programming construct that allows us to group name/value pairs. 5. CTS Delegate Types Delegates are equivalent to function pointers in C Language. 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. 6. CTS Member Types : A type member can be either constructor or finalizer or static constructor or nested type or operator or method or property or indexer or field or read only field or constant or event.

1.8.1

Built - In Data Types

.NET framework supports a well defined set of core data types. We know that there are different languages which are supported by .NET framework and each language is having its own syntax to declare an data type. But ultimately all those key words resolve to the same type defined in an assembly named mscorlib.dll. The following are the some of the data types defined in .NET Frame work Ravikiran

18

CHAPTER 1. PHILOSOPHY OF .NET

CTS Data Type System.Byte System.SByte System.Int16 System.Int32 System.Int64 System.UInt16 System.UInt32 System.UInt64 System.Single System.Double System.Object System.Char System.String System.Decimal System.Boolean

C# Keyword byte sbyte short int long ushort uint ulong float double object char string decimal bool

Table 1.1: The Built-in CTS Data Types

1.9

Common Language Specification

The Common Language Specification (CLS) is a set of rules that a given .NET-aware compiler must support to produce code that can be hosted by the CLR, while at the same time be accessed in a uniform manner by all languages that target the .NET platform. In many ways, the CLS can be viewed as a subset of the full functionality defined by the CTS. The CLS helps enhance and ensure language interoperability by defining a set of features that developers can rely on to be available in a wide variety of languages. The classes that follow the rules specified by CLS are termed as CLS-complaint classes. The classes defined in the .NET Framework class library are CLS-Compliant. The CLS describes a set of features that different languages have in common. CLS Compliance is especially important when creating software components that will be used by other languages. The most important rules, and which apply to public and protected members are 1. All types appearing in a method prototype must be CLS-compliant 2. Array elements must have a CLS-compliant element type. Arrays must also be 0-indexed 3. A CLS compliant class must inherit from a CLS-compliant class only

1.10

Common Language Runtime(CLR)

Common Language Runtime (CLR) is the execution environment for the .NET framework applications. CLR provides a unified environment for execution of programs written across different programming languages. While an application is running, the runtime environment is responsible Ravikiran

1.10. COMMON LANGUAGE RUNTIME(CLR)

19

for managing memory allocation, starting up and killing processes, and enforcing security policy, as well as satisfying any dependencies that the component might have on other components. 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 The CLR makes it easy to design components and applications whose objects interact across languages. Objects written in different languages can communicate with each other, and their behaviors can be tightly integrated.

1.10.1

Features of CLR

The following are some of the unique features of CLR 1. Cross Language Integration 2. Self Describing Components 3. Simple Deployment and Versioning 4. Integrated Security Services 5. Garbage Collection 6. High Performance 7. Reusability

Figure 1.2: Common Language Runtime Architecture

Ravikiran

20

CHAPTER 1. PHILOSOPHY OF .NET

1.11

Namespaces in .NET

A Namespace in Microsoft .Net is like containers of objects. They may contain unions, classes, structures, interfaces, enumerators and delegates. Main goal of using namespace in .Net is for creating a hierarchical organization of program. In this case a developer does not need to worry about the naming conflicts of classes, functions, variables etc., inside a project. In Microsoft .Net, every program is created with a default namespace. This default namespace is called as global namespace. But the program itself can declare any number of namespaces, each of them with a unique name. The advantage is that every namespace can contain any number of classes, functions, variables and also namespaces etc., whose names are unique only inside the namespace. The members with the same name can be created in some other namespace without any compiler complaints from Microsoft .Net. To declare namespace in C# .Net has a reserved keyword ”namespace”. If a new project is created in Visual Studio .NET it automatically adds some global namespaces. These namespaces can be different in different projects. But each of them should be placed under the base namespace System. The names space must be added and used through the using operator, if used in a different project. Example using System; namespace OutNamespace { namespace WorkNamespace { // Here we can be placed some classes, structures etc. class WorkItem { public WorkItem(){ } } } } In this example we create two namespaces. These namespaces have hierarchical structure - outer one named OutNamespace and the inner one called WorkNamespace. The inner namespace is declared with a C# .Net class WorkItem.

1.11.1

Accessing a Namespace

In C#, the ”using” keyword is used to refer any type declared in the namespace. They are two forms of using directive. The firsh is shown here

1. using name Ravikiran

1.12. DEPLOYING .NET FRAMEWORK

21

Here, name specifies the name of the namespace we want to access. All of the members defined in the specified namespace will now become the part of the current namespace. Using directive should be specified at the top of the file, prior to any other declarations. 2. using alias = name Here, alias becomes another name for the class or namespace specified by name

1.12

Deploying .NET Framework

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. 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.exethat 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 Microsoft. Once dotnetfx.exeis installed, the target machine will now contain the .NET base class libraries, .NET runtime ( mscoree.dll), and additional .NET infrastructure (such as the GAC).

Ravikiran

22

CHAPTER 1. PHILOSOPHY OF .NET

.NET Namespace System

System.Collections System.Collections.Generic

System.Windows.Forms System.Data System.Data.Odbc System.Data.OracleClient System.Data.OleDb System.Data.SqlClient System.Diagnostics System.Drawing System.Drawing.Drawing2D System.Drawing.Printing System.IO System.IO.Compression System.IO.Ports System.Net

Contents of Namespace Within System we can find numerous useful types dealing with built in data, mathematical computations, random number generation, environment ariables, and garbage collection, as well as a number of commonly used exceptions and attributes. These namespaces define a number of stock container objects (ArrayList, Queue, and so forth), 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 . This namespace contains types that facilitate the construction of traditional desktop GUI applications. These namespaces are used for interacting with databases using ADO .NET.

Here, you find numerous types that can be used to programmatically debug and trace your source code. Here, you find numerous types wrapping graphical primitives such as bitmaps , fonts , and icons , as w ell as printing capabilities. These namespaces include file I/O, buffering, and so forth. As of .NET 2.0, the IOnamespaces now include support compression and port manipulation. This namespace (as well as other related namespaces) contains types related to network programming (requests/responses, sockets, end points, and so on). These namespaces define types that support runtime type discovery as well as dynamic creation of types. This namespace provides facilities to allow .NET types to interact with ”unmanaged code” (e.g., C-based DLLs and COM servers) and vice versa. This namespace (among others) defines types used to build solutions that incorporate the .NET remoting layer. Security is an integr ated aspect of the .NET universe. In the security-centric namespaces y ou find numerous types dealing with permissions, cryptography, and so on. This namespace defines types used to build multithreaded applications.

System.Reflection System.Reflection.Emit System.Runtime. InteropServices System.Runtime.Remoting System.Security

System.Threading

Table 1.2: Built-in Namespaces in .NET Framework

Ravikiran

Chapter 2

Building C# Applications
2.1 C# Command Line Compiler

There are a number of techniques to compile C# source code. Most of the .NET programmers use Visual Studio in order to create .NET assemblies. Apart from visual studio, we can also use C# command-line compiler - csc.exe tool (where csc stands for C-Sharp Compiler). This tool is included with the .NET Framework 2.0 SDK. But using csc.exe alone is very difficult to build a large-scale application however it is important to understand the basics of how to compile *.cs files.

2.1.1

Configuring the C# Command-Line Compiler

Before using the csc.exe tool, we need to ensure that your development machine recognizes the existence of csc.exe. If our machine is not configured correctly, we are forced to specify the full path to the directory containing csc.exe. In order to specify the full of csc.exe, follow the following 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 (note each value in the Path variable is separated by a semicolon): C:/Windows/Microsoft.NET/Framework/v2.0.50215

2.1.2

Configuring Additional .NET Command-Line Tools

The other command line tools that are commonly used during .NET development are located in the following directory 23

24

CHAPTER 2. BUILDING C# APPLICATIONS

C:/Program Files/Microsoft Visual Studio 8/SDK/v2.0/Bin With these two paths established, we should now be able to run any .NET utility from any command window.

2.2

Building C# Applications using csc.exe

Once the path of csc.exe is set, the next goal is to write a simple C# application. Open any text editor and enter the following

using System; class TestApp { public static void Main() { Console.WriteLine(”Testing! 1, 2, 3”); } }

Save the above program in a convenient location (e.g, C:/CscExample) as TestApp.cs. Before compiling the above program, we have to know the different options of C# compiler. The following are the some of the options of C# Compiler. To compile TestApp.csinto a console Option /out Purpose This option is used to specify the name of the assembly to be 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 programs Main()method (in the case of an *.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. This option builds a single-file *.dllassembly. This option builds a module. Modules are elements of multifile assemblies Although you ar e free to build Windows-based applications using the /target:exe flag, the /target:winexeflag prevents a console window from appearing in the background. Table 2.1: Output-centric Options of the C# Compiler application named TestApp.exe, change to the dir ectory containing your source code file and enter the following command csc /target:exe TestApp.cs Ravikiran

/target:exe

/target:library /target:module /target:winexe

2.3. CSC.EXE RESPONSE FILES

25

When we compile the C# program, we can get the exe file of the compiled program having the same name of the file that is compiled. After compiling the TestApp.cs file, we will get TestApp.exe file and it can be executed by typing its file name C:/ TestApp.exe Testing! 1,2,3

2.2.1

Referencing External Assemblies

If our C# application refers to the external assemblies, then our application should be compiled with csc.exe by specifying the ”/r:” option. For example... using System; using System.Windows.Forms; class ExternalAssemblyDemo { public static void Main(string[] args) { MessageBox.Show(”Hello...”); } } Notice the reference to the System.Windows.Formsnamespace via the C# ’using’ keyword. So at the command prompt while compiling the above program we have to specify the ”/r:” option.

C:/ csc /r: ExternalAssemblyDemo.cs if you need to reference numerous external assemblies using c sc.exe, then we have to simply list each assembly using a semicolon-delimited list. For example csc /r:System.Windows.Forms.dll;System.Drawing.dll *.cs

2.3

csc.exe Response Files

If we are refering so many external assemblies, then we have to specify a lengthy options for the csc.exe tool. So to reduce he burden of typing long command line options, the C# command line compiler supports response files. Response files are nothing but text files which contain command line arguments to be feed to the compiler. Response files can save time and avoid typing errors. Response files end with the .rsp file extension.

Ravikiran

26

CHAPTER 2. BUILDING C# APPLICATIONS

For example, create the following text file named commandLine01.rsp: /r: MainAsm.dll /r: SecondAsm.dll /t: winexe /out: MainAppl.exe *.cs # Response file comment. Then, replace the lengthy command line switches with the name of the relevent response file for the current compilation using the @ symbol:

csc @commandLine01.rsp

2.3.1

The Default Response File(csc.rsp)

The C# compiler is defaultly associated with one response file having the name csc.rsp, which is located in the same directory where csc.exe is located. In this default response file contains numerous .NET assemblies are specified using the /r: flag. When we are building C# program using csc.exe, this file will be automatically referenced even when we supply our own response file. So even though if we are referring built in assemblies, there is no need to specify them explicitly by /r: flag. But, if we want to disable the automatic reading of csc.rsp we can specify the /noconfig option during the compile time. For example... csc @commandLine01.rsp /noconfig

2.4

Generating Bug Reports

The raw C# compiler provides a helpful flag named /bugreport. This flag will allows you to specify a file that will be populated (by csc.exe) with various statistics regarding our current build including any errors encountered during the compilation process. csc /bugreport:bugs.txt *.cs When we specify /bugreport, we will be prompted to enter correct information for the possible error(s) at hand, which will be saved (along with other details) into the file you specify. For Example...

using System; class DebugClass { static void Main(string[] args) Ravikiran

2.4. GENERATING BUG REPORTS

27

{ Console.WriteLine(”Hai”); Console.Readey(); //Compile Time Error } } In the above example, we have one error in the line 7. I have written Console.Readey() insetead of Console.ReadKey(). So, when we compile the above program as ...

csc /bugreport:BugFile.txt DebugClass.cs then will be prompted to enter corrective action for the error at hand. All This information is stored in file that is specified with the /bugreport flag (here it is BugFile.txt)

Ravikiran

28

CHAPTER 2. BUILDING C# APPLICATIONS

2.5

Remaining C# Compiler Options

C# compiler has many other flags that can be used to control how the resulting .NET assembly is to be generated. Some of those flags are listed below... Command Line Flag of csc.exe @ /help or /? /addmodule /baseaddress /bugreport /checked /codepage /debug /define /doc /filealign /fullpaths /lib / Purpose Allows you to specify a response file used during compilation Prints out the list of all command line flags of csc.exe Used to specify the modules to add to a multifile assembly Used to specify the preferred base address at which to load a *.dll Used to build text-based bug reports for the current compilation Used to specify whether integer arithmetic that overflows the bounds of the data type will cause an exception at run time Used to specify the codepage to use for all source code files in the compilation Forces csc.exe to emit debugging information Used to Define pre processor symbols Used to construct an XML Documentation Specifies the size of sections in the output file Specifies the absolute path to the file in the Compiler output Specifies the location of assemblies referenced 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 Suppresses compiler banner information when compiling the file Prevents the use of *.rsp files during the current compilation Suppress the compiler’s ability to generate specified warnings Specifies the output file Searches the subdirectories for source files to compile Specifies the format of the output file Used to automatically promote warnings to errors Compiles code that uses the C# ”unsafe” keyword Table 2.2: C# Command Line Compiler Options

/nolog /noconfig /nowarn /out /recurse /target /warnaserror /unsafe

Ravikiran

2.6. THE COMMAND LINE DEBUGGER (CORDBG.EXE)

29

2.6

The Command Line Debugger (cordbg.exe)

Cordbg.exe is a tool that provides many options that allow us to run our .NET assemblies under debug mode. We can view all these options by typing cordbg -?

Command Line Flag of cordbg.exe b[reak] del[ete] ex[i] g[0] si o[ut] so p[rint]

Purpose set or display current break points Removes one or more break points Exit the debugger Contiune the process of debugging until the next breakpoint Step into the next line Step out of the current function Step over the next line Print all loaded variables. Table 2.3: cordbg.exe flags

2.6.1

Debugging at Command Line

For example when we compile the DebugClass.cs

csc DebugClass.cs /debug and if there are no any compilation errors, the csc.exe tool will generates the DebugClass.pdb (pdb stands for Program Debug Database), DebugClass.exe files Once you have a valid *.pdb file, we can open a session with cordbg.exe by specifying your .NET assembly(here DebugClass.exe) as a command line argument (the *.pdb file will be loaded automatically): cordbg.exe testapp.exe cordbg DebugClass.exe At this point, you are in debugging mode, and may apply any number of cordbg.exe flags at the ”(cordbg)” command prompt When we finished debugging our application we can exit debugging mode by simply typing exit or just ex

2.7

Using Visual Studio - .NET IDE

Visual Studio allows you to build applications using any number of .NET-aware (and unaware) languages. Thus, you are able to use VS .NET when building C#, J#, VB.NET, MFC etc... The following are the some of the Key Elements of VS.NET Ravikiran

30

CHAPTER 2. BUILDING C# APPLICATIONS

2.7.1

The VS.NET Start Page

By default, the first thing you see when you launch Visual Studio .NET is the Start Page. In this start page we will be having different options like 1. Links to open recent projects 2. Tips to get how to start (Getting Started) 3. Visual Studio Head lines 4. Visual Studio Developer News (requires internet connection)

Figure 2.1: Visual Studio.NET 2005 Start page

2.7.2

Creating VS.NET Project Solution

Once Visual studio is opened, our next step is to either open recent project by clicking the required link shown on the start up page or to create a new project solution. Steps involved while creating new project 1. Click create project link from the start page or by choosing File — New — Project Menu selection 2. Next, New project Dialog will be appeared which allows us to choose different Project Types and Templates under the selected Project type. Ravikiran

2.7. USING VISUAL STUDIO - .NET IDE

31

3. After selecting the appropriate project type and template, specify the name of the project, location of project and also name of the solution in the corresponding texfields located at the bottom of New Project Dialog and then click ok button

Figure 2.2: New Project Dialog of VS.NET

Ravikiran

32

CHAPTER 2. BUILDING C# APPLICATIONS

Project Type Windows Application Class Library Windows Control Library ASP.NET Web Application ASP.NET Web service Web Control Library Console Application Window Services

Purpose This project type represents a Windows Forms application. This option allows you to build a single file assembly (*.dll). Windows This type of project allows you to build a single file assembly (*.dll) that contains custom Windows Forms Controls Select this option when you want to build an ASP.NET Web application. This option allows us to build .NET web service web service is block of code, reachable using HTTP requests VS .NET also allows you to build customized Web controls. These GUI widgets are responsible for emitting HTML to a requesting browser. Used to develop Console Application i.e. to create command window .NET allows you to build NT/2000 services. As you may know, these are background worker applications that are launched during the OS boot process. Table 2.4: Different Project Types available in VS.NET

2.8

Building VS.NET Test Application

Once we have given all the details like project name, project location and after pressing the ok button, a new folder will be created that contains number of starter files and project subdirectories. Generated Item /bin /Debug Purpose This folder contains the debug version of our compiled .NET assembly. If we configure a release build, a new folder (/bin /Release ) will be generated that contains a copy of our assembly. Under this folder there are numerous sub folders used by the VS.NET during compilation process. An *.ico file used to specify the icon for the current program This file allows us to establish assembly-level attributes for for our current project. This is our initial class file This file represents a C# project that is loaded into a given solution This file represents the current VS.NET solution

/obj /* App.ico AssemblyInfo.cs Class1.cs *.csproj *.sln

2.8.1

Examining the solution explorer window

Solution Explorer allows you to view items and perform item management tasks in a solution or a project. It also allows you to use the Visual Studio editors to work on files outside the context of a solution or project. The management of items displayed in Solution Explorer is based on an item’s relationship with project and solution containers. Items can be related in the following ways: Ravikiran

2.8. BUILDING VS.NET TEST APPLICATION

33

1. As project items, which appear under a project folder in Solution Explorer, for example, forms, source files, and classes. 2. As solution items, which appear in the Solution Items folder of Solution Explorer. 3. As miscellaneous files, which are files that are not associated with either a project or a solution and are displayed in the Miscellaneous Files folder.

Figure 2.3: VS.NET Solution explorer

2.8.2

Examining Class View

Class View displays the symbols defined, referenced, or called in the application we are developing. We can use Class View to open files and navigate directly to the lines where symbols appear. Class view tab shows object oriented view of our project.

Figure 2.4: VS.NET Class View

Ravikiran

34

CHAPTER 2. BUILDING C# APPLICATIONS

2.9

VS.NET Solution Properties

In the solution explorer window, right click on the name of the project and select properties. This launches the all-important Project Property Page.

Figure 2.5: Project Properties The box provides a number of settings, which map to various flags of the command line compiler. To begin, when we select the Application tab, we are able to configure the type of output file that should be produced by csc.exe. You are also able to configure which item in your application should be marked as the ”Startup object” (meaning, the class in the application that contains the Main() method). Finally, we can also allows you to configure the ’default’ namespace for this particular project.

Ravikiran

2.10. OTHER KEY ASPECTS OF VS.NET IDE

35

2.9.1

Properties Window

Figure 2.6: Project Properties Another important aspect of the IDE is the Properties window. This window allows you to interact with a number of characteristics for the item that has the current focus. This item may be an open source code file, a GUI widget, or the project itself.

2.10
2.10.1

Other Key Aspects of VS.NET IDE
Server Explorer Window

Figure 2.7: Sever Explorer Window The Server Explorer is a new development tool in Visual Studio .NET or in Visual Studio 2005 that is shared across development languages and projects. With the Server Explorer, you can connect to servers, as well as view and access their resources. For example, you can connect to, view and access the following resources: 1. Database Connections Ravikiran

36

CHAPTER 2. BUILDING C# APPLICATIONS

2. Servers 3. Crystal Reports 4. Event logs 5. Message Queues 6. Performance Counters 7. Window Services

2.10.2

XML-Related editing tools

XML is everywhere from XML Web Services to databases to config files to Office documents. Visual Studio .NET also provides numerous XML-related editors. When you open a file with an XML extension in Visual Studio, you will invoke its XML Editor. XML Editor comes with a full range of features you would expect from a Visual Studio editor, which includes IntelliSense, colorcoding, brace matching, outlining, and formatting. It provides full XML 1.0 syntax checking, end-tag completion, as well as DTD and XML schema support with real-time validation.

2.10.3

Object Browser Utility

The Object Browser allows you to select and examine the symbols available for use in projects. You can open the Object Browser from the View menu, or by clicking the Object Browser button on the main toolbar. There are three panes: an Objects pane on the left, a Members pane on the upper right, and a Description pane on the lower right. In the Objects pane, icons identify hierarchical structures such as .NET Framework and COM components, namespaces, type libraries, interfaces, enums, and classes. You can expand these structures to reveal ordered lists of their members. Properties, methods, events, variables, constants, and other contained items are listed in the Members pane. Details on the item selected in the Objects or Members pane appear in the Description pane.

Ravikiran

2.11. C# LANGUAGE’S PREPROCESSOR DIRECTIVES

37

Figure 2.8: Sever Explorer Window

2.10.4

Database Manipulation in Visual Studio

Integrated database support is also part of the VS .NET IDE. Using the Server Explorer window, you can open and examine any database object from IDE.

2.11

C# language’s preprocessor directives

C# preprocessor is fundamentally very similar to C preprocessor and the whole concept in C# has been taken from C language specification. C# preprocessor is fundamentally very similar to C preprocessor and the whole concept in C# has been taken from C language specification. A preprocessor directive must be the only instruction on a line. Preprocessing directives are lines in your program that start with ’#’. Whitespace is allowed before and after the ’#’. The ’#’ is followed by an identifier that is the directive name. For example, ’#define’ is the directive The C# language’s preprocessor directives are as follows

1. #if : #if lets us begin a conditional directive, testing a symbol or symbols to see if they evaluate to true. If they do evaluate to true, the compiler evaluates all the code between the #if and the next directive. #if symbol (operator symbol) where: Ravikiran

38

CHAPTER 2. BUILDING C# APPLICATIONS

symbol The name of the symbol we want to test. we can also use true and false. symbol can be prefaced with the negation operator. For example, !true will evaluate to false. operator (optional) You can use the following operators to evaluate multiple symbols: == (equality) != (inequality) && (and) —— (or) You can group symbols and operators with parentheses. #if, along with the #else, #elif, #endif, #define, and #undef directives, lets us to include or exclude code based on the condition of one or more symbols. This can be most useful when compiling code for a debug build or when compiling for a specific configuration. A conditional directive beginning with a #if directive must explicitly be terminated with a #endif directive. 2. #else : #else lets you create a compound conditional directive, such that, if none of the expressions in the preceding #if or (optional) #elif directives did not evaluate to true, the compiler will evaluate all code between #else and the subsequent #endif. 3. #elif 4. #endif 5. #define : #define lets you define a symbol, such that, by using the symbol as the expression passed to the #if directive, the expression will evaluate to true. 6. #undef : #undef lets you undefine a symbol, such that, by using the symbol as the expression in a #if directive, the expression will evaluate to false. 7. #warning : #warning lets you generate warning from a specific location in your code where text is the text of the warning that should appear in the compiler’s output. 8. #error : #error lets you generate an error from a specific location in your code where text is the text of the warning that should appear in the compiler’s output. 9. #line : #line lets you modify the compiler’s line number and (optionally) the file name output for errors and warnings #line [ number [”filename”] — hidden — default ] where number is the number we want to specify for the following line in a source code file. ”filename” (optional) The file name we want to appear in the compiler output. By default, the actual name of the source code file is used. The file name must be in double quotation Ravikiran

2.11. C# LANGUAGE’S PREPROCESSOR DIRECTIVES

39

marks (” ”). hidden - Hides the successive lines from the debugger until another #line directive is encountered. default - Resets the line numbering in a file.

10. #region #region lets you specify a block of code that we can expand or collapse when using the outlining feature of the Visual Studio Code Editor. 11. #endregion A #region block must be terminated with a #endregion directive. Main use of directives are • Conditional compilation - Using special preprocessing directives, we can include or exclude parts of the program according to various conditions. • Line control - If we use a program to combine or rearrange source files into an intermediate file, which is then compiled, you can use line control to inform the compiler of where each source line originally came from. • Error and Warning reporting - The directive ’#error’ causes the preprocessor to report a fatal error and the directive ’#warning’ is like the directive ’#error’, but causes the preprocessor to issue a warning and continue preprocessing. There are two method to define directive • Define in your C# program. • Define them at command line on compile time. Here is example for first way #define TEST using System; public class MyClass { public static void Main() { #if (TEST) Console.WriteLine(”TEST is defined”); #else Console.WriteLine(”TEST is not defined”); #endif } }

Ravikiran

40

CHAPTER 2. BUILDING C# APPLICATIONS

output TEST is defined In other way you can define it at command line. So program will be like this Example using System; public class MyClass { public static void Main() { #if (TEST) Console.WriteLine(”TEST is defined”); #else Console.WriteLine(”TEST is not defined”); #endif } }

At compile time user can define as below csc /define:TEST MyClass.cs Output TEST is defined

2.12

System Environment Class

System.Environment class provides information about, and means to manipulate, the current environment and platform. This class cannot be inherited. ome of the static members of this class are as follows: • Environment.OSVersion - Gets the version of the operating system • Environment.GetLogicalDrives() - method that returns the drives • Environment.Version - returns the .NET version running the application • Environment.MachineName - Gets name of the current machine • Environment.Newline - Gets the newline symbol for the environment • Environment.ProcessorCount - returns number of processors on current machine • Environment.SystemDirectory - returns complete path to the System Directory Ravikiran

2.12. SYSTEM ENVIRONMENT CLASS

41

• Environment.UserName - returns name of the entity that invoked the application • Environment.HasShutdownStarted -Ture if system is going to shut down

Ravikiran

42

CHAPTER 2. BUILDING C# APPLICATIONS

Ravikiran

Chapter 3

C# Language Fundamentals

3.1

Anatomy of C# Class

A class declaration in C# is composed of attributes, modifiers, the class name, base class and interfaces, and a body. Attributes, modifiers, and bases are all optional. The body of the class contains class members that can include constants, fields (or variables), methods, properties, indexers, events, operators, and nested types. Nested types are defined by class, interface, delegate, struct, or enum declarations within the class body.

3.1.1

Attributes

Attributes allows us to add custom information to the metadata for a class. It contains information about a class such as its name, its fields, and its methods, including their parameters and types. Metadata is essential to enable the .NET run time to load and use a class. The .NET run time reads the metadata through a process known as reflection. We can use reflection to access your own custom class metadata.

3.1.2

Modifiers

Modifiers allow us to control access to the class and to restrict the ability of the class to be instantiated or to serve as the base of another class. The class modifiers are public, protected, internal, private, abstract, sealed, and new. Using these modifiers, the following access levels can be specified: • public Access is unrestricted • protected Access is restricted to the containing class or to classes derived from it. • internal Access is restricted to the containing assembly (program). 43

44

CHAPTER 3. C# LANGUAGE FUNDAMENTALS

• protected internal Allow protected or internal access. You can also specify this access level as internal protected • private Access is restricted to the containing class • abstract The abstract modifier indicates that a class is incomplete and must be extended by a derived class in order to be instantiated. • sealed A sealed class can not be extended i.e. it cannot serve as a base class for another class. • new The new modifier may be applied only to a nested class or other class member, to indicate that it hides an inherited member of the same name. Hiding isnt necessarily an error, but the compiler will issue a warning. You can attach the new modifier to the nested class to tell the compiler that we are aware of the situation and that everything is okay Example using system; public class ClassAnatomy { int i; ClassAnatomy() { i=10; } static void Main(string[] args) { ClassAnatomy ca=new ClassAnatomy(); Console.WritLine(ca.i); } }

3.1.3

Main Method

Like in C or C++, the execution of C# program begins with Main method. In C#, we are having four overloaded forms of Main method. When a program starts, it looks for an entry point. This is the role of the Main() method. In fact, a program, that is an executable program, starts by, and stops with, the Main() method They are... • public static void Main(){} //No Return Type and No Arguments • public static void Main(string[] args){}//No Return Type and String argument • public static int Main(){} //Integer Return type and No Arguments Ravikiran

3.2. CONSTRUCTORS

45

• public static int Main(string[] args){} Integer Return type and string argument Processing Command Line Arguments There are two common ways to read command line arguments in C#. First, you can override the Main method with an array of strings, which are command line arguments. For example, the following code loops through the command line arguments and print them on the console. static void Main(string[] args) { foreach(string arg in args) { Console.WriteLine(arg); } Console.ReadLine(); } However, this is not only the way to read command line arguments. For example, if you do not want to override the Main method? Or access the command line arguments from non-Main method of your application, we have to use Environment Class, which has a static method called GetCommandLineArgs, which returns an array of strings containing the arguments. The following code reads the command line arguments using Environment.GetCommandLineArgs method. foreach (string arg in Environment.GetCommandLineArgs()) { Console.WriteLine(arg); } Specifying Command-Line Arguments in Visual Studio In Visual Studio, double-click the Properties icon from Solution Explorer and select the Debug tab on the left side. From here, specify values using the ”Command line arguments” text box

3.2

Constructors

A constructor is a member that implements the actions required to initialize an instance of a class. Broadly speaking, it is a method in the class which gets executed when its object is created i.e. a constructor is invoked when you use the ”new” operator. Constructors are used for initializing the members of a class whenever an object is created with the default values for initialization. If a class is not defined with the constructor then the CLR (Common Language Runtime) will provide an implicit constructor which is called as Default Constructor. A class can have any number of constructors provided they vary with the number of arguments that are passed, which is they should have different signatures. Ravikiran

46

CHAPTER 3. C# LANGUAGE FUNDAMENTALS

Figure 3.1: Passing Command line arguments in Visual Studio • Constructors do not return a value • Constructors can be overloaded except static constructors • Constructors will be having the same name as that of its containing class • Constructor cant be get inherited • A class has atleast one constructor also known as default constructor [a constructor without parameter]

3.2.1

Types of Constructors

In C#, we are having the following different types of constructors... • Default Constructor A constructor that takes no parameters is called a default constructor. Default constructors are invoked whenever an object is instantiated by using the new operator and no arguments are provided to new. • Parameterized Constructors At times, we will require initializing class members during instantiation and this is the time where parameterized constructor will come into picture. It follows the same rules as default constructor and will have parameters. Note A default constructor should be explicitly declared while declaring parameterized constructor. Ravikiran

3.2. CONSTRUCTORS

47

• Static Constructors A static constructor is used to initialize any static data, or to perform a particular action that needs performed once only. It is called automatically before the first instance is created or any static members are referenced. Static constructors will have following properties... 1. A static constructor does not take access modifiers or have parameters 2. A static constructor is called automatically to initialize the class before the first instance is created or any static members are referenced. 3. A static constructor cannot be called directly 4. The user has no control on when the static constructor is executed in the program. • Private Constructors A private constructor is a special instance constructor. It is commonly used in classes that contain static members only. If a class has one or more private constructors and no public constructors, then other classes (except nested classes) are not allowed to create instances of this class. Private constructors are used to prevent the creation of instances of a class when there are no instance fields or methods, such as the Math class. Example public class CounterClass { private CounterClass() { } public static int i; public static int IncrementCount() { return ++i; } } class CounterClass { static void Main() { // If you uncomment the following statement, it will generate // an error because the constructor is inaccessible: // Counter aCounter = new Counter(); // Error CounterClass.i = 100; CounterClass.IncrementCount(); System.Console.WriteLine(”Current Value: {0 }”, CounterClass.i); } }

Ravikiran

48

CHAPTER 3. C# LANGUAGE FUNDAMENTALS

3.3

System.Console

Represents the standard input, output, and error streams for console applications. This class cannot be inherited. As its name implies, the Console class encapsulates input, output, and error stream manipulations for console-based applications. The console is an operating system window where users interact with the operating system or a text-based console application by entering text input through the computer keyboard, and reading text output from the computer terminal. Some of the properties of Console are... Console Member BackgroundColor ForegroundColor BufferWidth BufferHeight Clear() WindowHeight WindowTop WindowLeft Title CursorVisible Purpose These properties set the background/foreground colors for the current output. They can be assigned any member of the ConsoleColor enumeration These properties control the height/width of the consoles buffer area. This method clears the buffer and console display area These properties control the dimensions of the console in relation to WindowWidth the established buffer.

Gets or sets the title to display in the console title bar. Gets or sets a value indicating whether the cursor is visible.

3.3.1

Basic Input and Output with the Console Class

When a console application starts, the operating system automatically associates three I/O streams with the console. Our application can read user input from the standard input stream; write normal data to the standard output stream; and write error data to the standard error output stream. These streams are presented to our application as the values of the In, Out, and Error properties Console class defines a set of methods to capture input and output. All these methods are static methods and hence we can directly call these methods at class level. Console Member Read ReadKey ReadLine Write WriteLine Purpose Reads the next character from the standard input stream. Obtains the next character or function key pressed by the user. Reads the next line of characters from the standard input stream. Writes the text representation of the specified value or values to the standard output stream Writes the specified data, followed by the current line terminator, to the standard output stream

Table 3.1: Console Class Properties that support Read and write operations

Ravikiran

3.3. SYSTEM.CONSOLE

49

using System; using System.Collections.Generic; using System.Text; namespace Environment { class Program { static void Main(string[] args) { Console.ForegroundColor = ConsoleColor.DarkRed; Console.WindowWidth = 50; Console.Title = ”Ravi kiran Console”; Console.WriteLine(”Ravi kiran”); Console.BackgroundColor = ConsoleColor.DarkGray; Console.WriteLine(”Press any key to get beep sound”); Console.ReadKey(); Console.Beep(); Console.BufferWidth = 100; Console.WriteLine(”Press any key to clear the screen”); Console.ReadKey(); Console.Clear(); Console.WriteLine(”Press any key to reset the screen color”); Console.ReadKey(); Console.ResetColor(); } } }

3.3.2

Formatting Console output

.NET introduces a new style of string formatting which is similar to the ’C’ language printf statement. For example... static void Main(string[] args) { int age=28; string name=”Ravi kiran”; Console.WriteLine(”I am {0}, having age {1}”,name,age); } 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). Ravikiran

50

CHAPTER 3. C# LANGUAGE FUNDAMENTALS

The remaining parameters to WriteLine() are simply the values to be inserted into the respective placeholders. It is also permissible for a given placeholder to repeat within a given string. For example, Console.WriteLine(”{0} is simple. {0} is like C++ ”,”.NET”); The above statement prints ” .NET is simple. .NET is like C++ If we require more elaborate formatting, each placeholder can optionally contain various format characters either in upper case or lower case.

3.3.3

Formatting Numbers
type Currency decimal (whole number) exponent /scientific fixed point general number round trippable hexadecimal format {0:c} {0:d} {0:e} {0:f} {0:g} {0:n} {0:r} {0:x4} output (double 1.2345) $ 1.23 System.FormatException 1.234500e+000 1.23 1.2345 1.23 1.23 System.FormatException output (int -12345) $ 12,345.00 -12345 -1.234500e+004 -12345.00 -12345 -12,345.00 System.FormatException ffffcfc7

Specifier C or c D or d E or e F or f G or g N or n R or r X or x

3.3.4

Custom Number Formatting
type zero placeholder digit placeholder decimal point placeholder thousand separator percentage format {0:00.000} {0:#.##} {0:0.0} {0:0,0} {0:0%} output (double 1234.56) 1234.560 1234.56 1234.6 1,235 123456%

Specifier 0 # . , %

Ravikiran

3.3. SYSTEM.CONSOLE

51

3.3.5

Date Formatting
type Short Date Long Date Short Time Long Time Full date and time Full date and time (long) Default date and time Default date and time (long) Day /Month Month /Year output (June 8, 1970 12:30:59) 08/06 /1970 08 June 1970 12:30 12:30:59 08 June 1970 12:30 08 June 1970 12:30:59 08 /06 /1970 12:30 08 /06 /1970 12:30:59 8 June June 1970

Specifier d D t T f F g G M Y

3.3.6

Custom Date Formatting
type Day Short Day Name Full Day Name 2 digit hour 2 digit hour (24 hour) 2 digit minute Month Short Month name Month name seconds AM /PM 2 digit year 4 digit year seperator, e.g. 0:hh:mm:ss seperator, e.g. 0:dd /MM /yyyy 08 /06 /1970 output (June 8, 1970 12:30:59) 08 Mon Monday 12 12 30 06 Jun June 59 PM 70 1970 12:30:59

Specifier dd ddd dddd hh HH mm MM MMM MMMM ss tt yy yyyy : /

Ravikiran

52

CHAPTER 3. C# LANGUAGE FUNDAMENTALS

3.4

Default values for variables

The following table shows the default values of value types returned by the default constructors. Default constructors are invoked by using the new operator. All the value types that are declared Value Type bool byte char decimal double float int long sbyte short ulong ushort Default Value false 0 ’\0’ 0.0M 0.0D 0.0F 0 0L 0 0 0 0

in the class are initialized to their default values, whereas all other reference types are initialized to null.

3.5

Variable Scope

The scope of a variable determines its visibility to the rest of a program. When we declare a variable in any method, this means that the variable is available to use within the method but when control passes to another method the variable becomes unavailable. There are other possibilities for a variable’s scope. For example, a variable can be declared within a loop or other code structure and then be only visible to the code within the structure. A wider scoped variable could be declared at class-level so that it can be used by any method within the class. In fact, a variable’s scope is always the full extent of the code block, delimited by braces {}, that it is declared within. 1. Class-Level Scope Variables that are defined at the class level become available to any non-static method within the class. 2. Method-Level Scope Variables declared within the main code block of a method are available for use by any other part of the method, including nested code blocks 3. Nested Scope Variables declared within a nested scope are not available to those outside of their code block Ravikiran

3.6. MEMBER VARIABLE INITIALIZATION

53

3.6

Member Variable Initialization

Class tends to have member variables. Normally in order to initialize these variables, we will use constructors. A class can contain more than one one constructor (overloaded constructors), and in each constructor we have to write same initialization code. This is particularly necessary if we do not wish to accept the default values assigned to class members. For example, if an integer variable in our class should always begins with default value of ”13” then we could write class MemberInitializationDemo { int i; string name; MemberInitializationDemo() { i=9; } MemberInitializationDemo(string val) { i=9; name=””; } static void Main(string[] args) { MemberInitializationDemo m1,m2; m1=new MemberInitializationDemo(); m2=new MemberInitializationDemo(”Ravi kiran”); } } The main method in the above example contains two objects (m1 and m2) for the class ”MemberInitializationDemo”. When memory is alloted for the object m1, m1.i will be having value of 9 and m1.name will be having value of empty string where as for m2, m2.i will also hold the value of 9 but m2.name contains ”Ravi kiran”.

3.7
3.7.1

Value Types and Reference Types
Value Types

C# provides a set of different data types. The data types in C# are divided into two categories Value Types and Reference Types. A variable that is a value type, stores the data, while a variable of a reference type stores a reference to the data. Variable that are based on value types directly contain a values. Assigning one value type variable to another copies the contained Ravikiran

54

CHAPTER 3. C# LANGUAGE FUNDAMENTALS

value. All value types are derived implicitly from the System.ValueType. The value types consist of two main categories: 1. Structs Structs fall into these categories • Numeric types – Integral Types – Floating-Point types – Decimal • bool • User defined structs 2. Enumerations

3.7.2

Reference Types

Variables of reference types, referred to as objects, store references to the actual data. When an assignment occurs between reference variables, only the reference is copied i.e actual value remains the same in memory and there are now two references to the same memory location Reference Type variables are allocated on the Managed Heap. CLR manages the Heap memory for reference type. Memory allocation for an object should be done by using the ”new” keyword. Objects are allocated onto the managed heap, where they are automatically deallocated by the runtime at ”Some time in the future”. Garbage collection is automated in C#. If the Managed heap does not have sufficient memory to allocate a requested object, a garbage collection will occur. All class objects, interface objects and delegates are reference type variables. The following program demonstrates the Value and Refernce Types using System; class ValueAndRefernceTypes { int i; static void Main(string[] args) { int temp=10; ValueAndRefernceTypes v=new ValueAndRefernceTypes(); //Assigning Value Type to a value type i.e. value is copied //from one variable to another variable int temp1=temp;

Ravikiran

3.8. BOXING AND UNBOXING

55

//Assigning Reference Type to a Reference type. Here, only //reference is copied from one variable to another variable //i.e Variables (v1 and v2) will be pointing to same memory location ValueAndRefernceTypes v1=v; temp1=50; v1.i=100; Console.WriteLine(”Temp value is {0}”,temp); Console.WriteLine(”Temp1 value is {0}”,temp1); Console.WriteLine(”Temp value is {0}”,v.i); Console.WriteLine(”Temp value is {0}”,v1.i); } }

3.8

Boxing and Unboxing

Boxing and unboxing is a essential concept in .NET. With Boxing and unboxing one can link between value-types and reference-types by allowing any value of a value-type to be converted to and from type object

3.8.1

Boxing

Converting a value type to reference type is called Boxing. When the CLR boxes a value type, it wraps the value inside a System.Object and stores it on the managed heap.In the following example, the integer variable i is boxed and assigned to object o. int i=10; object o = (object) i; //boxing Boxing is used to store value types in the garbage-collected heap. Boxing is an implicit conversion of a value type to the type object or to any interface type implemented by this value type. Boxing a value type allocates an object instance on the heap and copies the value into the new object. The following statement implicitly applies boxing operation on variable i int i=10; object o = i; //implicit boxing

Ravikiran

56

CHAPTER 3. C# LANGUAGE FUNDAMENTALS

3.8.2

UnBoxing

Unboxing is the opposite operation to boxing. An unboxing conversion permits an explicit conversion from reference type to any value-type. An unboxing operation consists of 1. Checking the object instance to make sure it is a boxed value of the given value type 2. Copying the value from the instance into the value-type variable When an object box is cast back to its original value type, the value is copied out of the box and into the appropriate storage location Example for Boxing and Unboxing using System; class Program { struct Point { public int x, y; public Point(int x, int y) { this.x = x; this.y = y; } } static void Main(string[] args) { Point p = new Point(10, 20); object o = p; Console.WriteLine(((Point)o).x); Point p1 = (Point)o; Console.WriteLine(p1.x); } }

3.9

System.Object

In C# the Object class is the ultimate base class of every type that all other other types directly or indirectly derive from it. the object classThe Object class provides a number of methods that can be called on all objects 1. Equals The Equals method of the object class provides a default implementation that compares two reference type objects for reference equality. Reference equality occurs when two reference type objects refer to the same object. Ravikiran

3.9. SYSTEM.OBJECT

57

using System; class Program { int i; Program(int j) { j = i; } void display() { Console.WriteLine(”Value of I is ” + i); } static void Main(string[] args) { Program p = new Program(10); Program p1 = new Program(10); Console.WriteLine(p.Equals(p1)); Program p2=p; Console.WriteLine(p.Equals(p2)); } } In above example p and p1 are two different objects (i.e. both of these objects ae pointing to different memory location), so p.Equals(p1) will returns false. But, the objects p2 and p are pointing to the same memory location and hence p.Equals(p2) will returns true. Some times it is necessary to check whether the two objects have same values for their fields instead of checking for their memory address. So for this purpose, we have to override the Equals method. For example, if we include the following code in the above example, the Equlas method will return true if both objects will have the same value for i. (Even though both objects refer to different memory locations, if the value of i is same it will returns true or else false) override public bool Equals(Program p) { if(i==p.i) return true; return false; } 2. ReferenceEquals In the object class, the Equals and ReferenceEquals methods are semantically equivalent, except that the ReferenceEquals works only on object instances. Ravikiran

58

CHAPTER 3. C# LANGUAGE FUNDAMENTALS

The ReferenceEquals method is static. For example, Object.ReferenceEquals(p,p1) If both p and p1 refer to same memory location, then it will returns true else it will return false. 3. GetType GetType is the basis for using reflection in .NET. It returns a Type object, describing the object it was called on. The GetType method is also useful if we get an object at runtime and we don’t know what it’s type is. For example Console.WriteLine(p.GetType()) The above statement will prints the name of the Type (Here it is ”Program”). 4. GetHashCode The GetHashCode method makes any object usable in a Hashtable or any hashing algorithm. Since the default algorithm supplied by the GetHashCode method of the object class is not guaranteed to be unique, you should override GetHashCode in your custom types. For example Console.WriteLine(p.GetHashCode()) The above line will prints the hash code of object ”p” 5. ToString The purpose of the ToString method is to return a human readable representation of a type. The default implementation in the object class returns a string with the name of the runtime type of the object. For example Console.WriteLine(p) The above line will prints the name of Type. Here it is ”Program”. The ToString method is a virtual method, and so we can override this method to return our own string. For example override public string ToString() { return ”The value of I is ”+i; } Now Console.WriteLine(p) method will prints ”The value of I is 10” 6. MemberwiseClone Whenever we need to create a shallow copy of our type, we use the MemberwiseClone method. A shallow copy is a bitwise copy of our type. As such, if we perform a MemberwiseClone on our class, it will make a copy of the type and all contained value types and references types. Since the MemberwiseClone method is not virtual, we can not override it in derived classes. For example.. Ravikiran

3.10. CONSTANT DATA

59

Program p3=(Program)p.MemberWiseClose(); The above statement will creates a new object p3 exactly of type p. But p and p3 will point to different memory locations (It is not similar to Program p3=p where p3 and p will refer to same memory location). As MemberwiseClone returns object, we have to convert explicitly to the type of object we are going to convert.

3.10

Constant Data

In C# constant data can be specided in two ways • by using ’const’ modifier • by using ’readonly modifier

3.10.1

const modifier

Constants are fields whose values are set at compile time and can never be changed. A C# constant is similar to a variable in that it gives a defined name to a value. However, a constant differs from a standard variable because once defined, the value assigned to the constant can never be changed. A constant is declared using similar syntax to any other variable. However, to indicate that the value is fixed and may not be changed at run-time, the const keyword is used as a prefix to the data type for example const int PI=3.14; Constants are declared with the const modifier. Only the C# built-in types (excluding System.Object) may be declared as const. C# does not support const methods, properties, or events. Constants can be marked as public, private, protected, internal, or protected internal. These access modifiers define how users of the class can access the constant. Constants are accessed as if they were static fields because the value of the constant is the same for all instances of the type. we do not use the static keyword to declare them. using System; class Program { const int PI=3.14; //By default const variables are static static void Main(string[] args) { Console.WriteLine(Program.PI); } }

Ravikiran

60

CHAPTER 3. C# LANGUAGE FUNDAMENTALS

3.10.2

By using readonly modifer

A readonly member is like a constant in that it represents an unchanging value. The difference is that a readonly member can be initialized at runtime, in a constructor as well being able to be initialized as they are declared. for example using System; class ConstantDemo { readonly int A=10; readonly int B; readonly int C; ConstantDemo() { B=20; C=Console.ReadLine(); } } • Like constant members, readonly members are not implicitly static, and therefore the static keyword can be applied to a readonly field explicitly if required. • A readonly member can hold a complex object by using the new keyword at initialization. • readonly members cannot hold enumerations.

3.11

Iteration Constructs in C#

C# provides a number of the common loop statements: • while • do-while • for • foreach

3.11.1

while loop

A ’while’ loop executes a statement, or a block of statements wrapped in curly braces, repeatedly until the condition specified by the boolean expression returns false. For instance, the following code Ravikiran

3.11. ITERATION CONSTRUCTS IN C#

61

int a=1; while(a <4) { Console.WriteLine(a); a++; } produces the follwing output 1 2 3

3.11.2

do-while loops

A ’do-while’ loop is just like a ’while’ loop except that the condition is evaluated after the block of code specified in the ’do’ clause has been run. So even where the condition is initially false, the block runs once. For instance, the following code outputs ’4’: int a=4; do { Console.WriteLine(a); }while(a <3);

3.11.3

for loops

The statements in the for loop repeat continuously for a specific number of times. The while and do-while loops repeat until a certain condition is met. The for loop repeats until a specific count is met. Use a for loop when the number of repetition is know, or can be supplied by the user. The coding format is: for(startExpression; testExpression; countExpression) { block of code; } The startExpression is evaluated before the loop begins. It is acceptable to declare and assign in the startExpression (such as int x = 1;). This startExpression is evaluated only once at the beginning of the loop. The testExpression will evaluate to true or false. While TRUE, the body of the loop repeats. When the testExpression becomes FALSE, the looping stops and the program continues with the statement immediately following the for loop body in the program code. The countExpression executes after each trip through the loop. The count may increase /decrease by an increment of 1 or of some other value. Ravikiran

62

CHAPTER 3. C# LANGUAGE FUNDAMENTALS

3.11.4

foreach loop

syntax: foreach(variable1 in variable2) { //Statements } The ’foreach’ loop is used to iterate through the values contained in a collection. When a ’foreach’ loop runs, the given variable1 is set in turn to each value exposed by the object named by variable2. for example int[] a=1,2,3; foreach(int b in a) { Console.WriteLine(b); } The main drawback of ’foreach’ loops is that each value extracted (held in the given example by the variable ’b’) is read-only.

3.12

Flow Control statements in C#

C# provides two types of statements that control the flow of control in a program • Jump Statements • Selection Statements

3.12.1

Jump Statements

The jump statements include • break • continue • goto • return • throw break The ’break’ statement breaks out of the ’while’ and ’for’ loops and the ’switch’ statements. The output of the following loop is the numbers from 0 to 4. Ravikiran

3.12. FLOW CONTROL STATEMENTS IN C#

63

int i=0; while(true) { Console.WriteLine(i); if(i==5) break; i++; } continue The ’continue’ statement can be placed in any loop structure. When it executes, it moves the program counter immediately to the next iteration of the loop. The following code example uses the ’continue’ statement to count the number of values between 1 and 100 inclusive that are not multiples of seven. At the end of the loop the variable y holds the required value. int y=0; for(int x=1;x <101;x++) { if((x%7)==0) continue; y++; } goto The ’goto’ statement is used to make a jump to a particular labelled part of the program code. We can use a ’goto’ statement to construct a loop, as in the following example (but again, this usage is not recommended): int a=0; start: Console.WriteLine(a); a++; if(a <5 ) goto start; Return Statement The ’return’ statement is used in the method to return some value to the calling part of the program. When the return statement is encountered in the method, method will stop and return a value. The control will be transfered to the calling part of the program and starts executes the statements thereafter. Ravikiran

64

CHAPTER 3. C# LANGUAGE FUNDAMENTALS

throw statement Throw statement is used for handling exceptions. Throw statement is used in the try block. When throw statement is encountered in the middle of try block, then the control will be transferred to the appropriate catch block.

3.12.2

Selection Statements

In C#, there are two types of selection statements. 1. if-else statements ’If-else’ statements are used to run blocks of code conditionally upon a boolean expression evaluating to true. The ’else’ clause, present in the following example, is optional. if(a==10) Console.WriteLine(” A is equal to 10”); else Console.WriteLine(”A is not equal to 10”); Different types of if statements are... • simple if • if-else statements • Nested if statements • Ladder if-else statements(if-else-if....) 2. Switch statements The switch statements help to control complex conditional and branching operations. The switch statement transfers control to a statement within its body. Syntax switch(expression) { case (constantExpression): //Statements break; . . . case (constantExpression): //Statements break; default: //statements break } Ravikiran

3.13. C# OPERATORS

65

In order to come out of a particular case, we have to use break statement and program will comes out of the switch body. Without break, the program continues to the next case, executing the statements until a break or the end of the statement is reached. In some situations, this continuation may be desirable. The default statement is executed if no case constant-expression is equal to the value of switch ( expression ). If the default statement is omitted, and no case match is found, none of the statements in the switch body are executed. There can be at most one default statement. The default statement need not come at the end; it can appear anywhere in the body of the switch statement. A case or default label can only appear inside a switch statement. The type of switch expression and case constant-expression must be integral. The value of each case constant-expression must be unique within the statement body. The case and default labels of the switch statement body are significant only in the initial test that determines where execution starts in the statement body. Switch statements can be nested.

3.13

C# Operators

C# provides a large set of operators, which are symbols that specify which operations to perform in an expression. The following are the C# operators. • Unary Operators Unary operators are those which will take only one operand. The various unary operators in C# are +, -, !, , ++x, –x, true, false, & , sizeof • Binary Operators Binary operators are those which will take two operands. * , /, % , + , • Shift Operators Shift operators are those used to shift bits of a number (in binary number) towards are right or left <<, >> • Relational Operators These operators are used to test the relation of two operands. <, >, >= , <= , == , != , is , as • Conditional And This operator returns true if both the expressions on either side of this operator evaluates to true else it will returns false & & - Logical AND operator

Ravikiran

66

CHAPTER 3. C# LANGUAGE FUNDAMENTALS

• Conditional Or This operator returns true if either on of the expressions on either side of this operator evaluates to true. If both expressions evaluates to false, it will also returns false. || - Logica OR operator • Conditional operatoar This operator is similar to if-else statement. ?: - Conditional operator (or) terenary operator • Assignment operatoars These operators are used to assign values to a variable. The following are the assignment operators available in C# = , += , -= , *= , /= , % = , & = , |=, ˆ= , <<= , >>=

3.14

Defining Custom Class Methods

Custom classes are those classes which we define i.e. those are not part of .NET library. We can define our own methods in our own classes. These custom methods may or may not have return type ( if no return type, then void is used as return type ). Custom methods also may or may not take parameters, may be declared as static or non static. We can also specify the following various access modifiers to the custom methods 1. private : Method that is declared as private can be accessed only by the type in which the method is defined. (It is the default visiblity level) 2. public : Method that is declared as public can be accessed by any class or object i.e. there is no restriction in accessing the public method 3. internal : Methods that are declared as internal can be accessed as public by all types in a containing assembly. 4. protected : Here the access is limited to the containing class or types derived from the containing class. 5. protected internal : Access is limited to the current assembly or types derived from the containing class.

3.15

Static Methods

A C# class can contain both static and non-static methods. When we declare a method with the help of the keyword static, it becomes a static method. A static method belongs to the class rather than to the objects of the class. Hence static method are also known as class method and non-static method are known as instance methods. Ravikiran

3.16. METHOD PARAMETER MODIFIERS IN C#

67

A static method is callable on a class even when no instance of the class has been created. If any instances of the class are created, they cannot be used to access the static member. Static members are often used to represent data or calculations that do not change in response to object state; for instance, a math library might contain static methods for calculating sine and cosine. Static class members are declared using the static keyword before the return type of the member, for example: static int Sum(int a, int b) return a+b; Static members are initialized before the static member is accessed for the first time, and before the static constructor, if any is called. To access a static class member, use the name of the class instead of a variable name to specify the location of the member. Static Fields Static fields can be declared as follows by using the keyword static. class MyClass { public static int x; public static int y = 20; } When we declare a static field inside a class, it can be initialized with a value as shown above. All un-initialized static fields automatically get initialized to their default values when the class is loaded first time. Inside a C# class, member functions can also be declared as static. But a static member function can access only other static members. They can access non-static members only through an instance of the class. We can invoke a static member only through the name of the class. In C#, static members can’t invoked through an object of the class as like in C++ or JAVA.

3.16

Method Parameter Modifiers in C#

There are four different kinds of parameters in C#: • value parameters (the default) • reference parameters (which use the ref modifier) • output parameters (which use the out modifier) • parameter arrays (which use the params modifier) we can use any of them with both value and reference types. Ravikiran

68

CHAPTER 3. C# LANGUAGE FUNDAMENTALS

3.16.1

Value parameters

; By default, parameters are value parameters. This means that a new storage location is created for the variable in the function member declaration, and it starts off with the value that you specify in the function member invocation. If you change that value, that doesn’t alter any variables involved in the invocation. For instance, if we have: public class ValueReferenceType { static void change (int x) { x += 10; } public static void Main (string[] args) { int x=10; change(x); Console.WriteLine (”value of x is {0}”,x); } } In the above example, the value of x is not changed in main method even when we call the function change(). This is because, a new memory is created for the parameter when the function is called and all the changes will occur in that new memory location and that change is not reflected in the main method. So the output of above program will be 10 but not 20.

3.16.2

Reference parameters

Reference parameters don’t pass the values of the variables used in the function member invocation - they use the variables themselves. Rather than creating a new storage location for the variable in the function member declaration, the same storage location is used, so the value of the variable in the function member and the value of the reference parameter will always be the same. Reference parameters need the ref modifier as part of both the declaration and the invocation - that means it’s always clear when you’re passing something by reference. Reference parameters are passed using the keyword ref

Ravikiran

3.16. METHOD PARAMETER MODIFIERS IN C#

69

Let’s look at our previous examples, just changing the parameter to be a reference parameter... public class ValueReferenceType { static void change (ref int x) { x += 10; } public static void Main (string[] args) { int x=10; change(x); Console.WriteLine (”value of x is {0}”,x); } } Now the above program will produces output 20.

3.16.3

Output Parameters

Like reference parameters, output parameters don’t create a new storage location, but use the storage location of the variable specified on the invocation. Output parameters need the out modifier as part of both the declaration and the invocation - that means it’s always clear when you’re passing something as an output parameter. Output parameters are very similar to reference parameters. The only differences are.. • The parameter is considered initially unassigned • The parameter must be assigned a value before the function member completes normally. public class ValueReferenceType { static void change (ref int x,out int y) { x += 10; y=10; } public static void Main (string[] args) { int x=10; int y; change(x,y); Console.WriteLine (”value of x is {0} and y is {1} ”,x,y); } } Ravikiran

70

CHAPTER 3. C# LANGUAGE FUNDAMENTALS

The above program will produces 10 and 20 as output. Notice that even though we didnt initialize the y variable, it will get initiailized in the method. Genrally out parameters are used to return multiple values from the method.

3.16.4

Parameter arrays

Parameter arrays allow a variable number of arguments to be passed into a function member. The definition of the parameter has to include the params modifier, but the use of the parameter has no such keyword. A parameter array has to come at the end of the list of parameters, and must be a single-dimensional array. When using the function member, any number of parameters (including none) may appear in the invocation, so long as the parameters are each compatible with the type of the parameter array. Alternatively, a single array may be passed, in which case the parameter acts just as a normal value parameter. For example:

public class ValueReferenceType { void ShowNumbers (params int[] numbers) { foreach (int x in numbers) Console.WriteLine (x+” ”); } public static void Main (string[] args) { change(10,11,12,13,14,15,16); change(34,45,2); } }

3.17

Arrays in C#

An array is a collection of similar data types stored in adjacent memory locations. Though the syntax of declaring and using a C# array is more or less similar to that of C/C++, they are actually created as objects of the System.Array class. Hence arrays in C# fall in the category of reference types. Like any other reference type, an array object refers to a memory space allocated on the heap. Following code fragment shows how to declare and initialise an array. int[] a, b ; a = new int [10] ; b = new int [] { 0, 1, 2, 3, 4 } ; Ravikiran

3.17. ARRAYS IN C#

71

3.17.1

Array Bounds Checking

In C# checking the array bounds is not the programmer’s responsibility. If the array bounds are exceeded, the .NET runtime informs the application about it by throwing an exception. An exception is a runtime error caused by fatal errors like array bounds out of range, using an invalid reference, etc. Thus, following code would never work in C#. int[ ] a = { 1,2, 3, 4 } ; a [ 4 ] = 10 ; Although compiler would not report any error .NET runtime would throw an exception.

3.17.2

Multi Dimensional Arrays

Apart from single dimension array, C# provides multidimensional arrays, also called rectangular arrays and jagged arrays. This is how we can declare a 2D array. int [ , ] arr1 = new int [ 4, 4 ] ; arr1 = new int [ 4, 4 ] ; int [ , ] arr2 = { { 3, 5, 7, 9 }, { 11, 13, 15, 17 } } ;

3.17.3

System.Array class

The difference between C and C++ arrays is the fact that every array we create is automatically derived from System.Array. This class defines a number of helpful methods that make working with arrays much more palatable. 1. BinarySearch This is a static method of System.Array class. It takes two arguments one is an array type and one is object type. It will searches the array for the given object and if the object is found it will return the index of that object else it will return the value less than 0 (negative index). For example static void Main() { int[] a=10,20,30,40,15; Console.WriteLine(Array.BinarySearch(a,30)); } The above example prints the value 2 as 30 is at 2nd position. 2. Clear : Clear is a static method of Array class. Sets a range of elements in the Array to zero, to false, or to a null reference depending on the element type. It will take three parameters • Array type - whose elements has to be cleared • index - specifying the start index of the range of elements to be cleared • length - specifies the number of elements to be cleared Ravikiran

72

CHAPTER 3. C# LANGUAGE FUNDAMENTALS

static void Main() { int[] a=10,20,30,40,15; Array.Clear() } 3. Clone : Creates a shallow copy of the Array. The return type of this method is an object. So we have to use explicitly type cast into the required type. For example.. static void Main() { int[] a=10,20,30,40,15; int[] b; b=(int[]) a.Clone(); } 4. CopyTo : Copies all the elements of the current one-dimensional Array to the specified one-dimensional Array. It takes two parameters • Array Type - It is the destination array to which we have to copy elements • intex - Specifies the index from which copy has to begin static void Main() { int[] a=10,20,30,40,15; int[] b=new int[4]; a.CopyTo(b,0); } In the above example, all the elements in a will be copied into b starting at 0th index of b. 5. GetLength Gets a 32-bit integer that represents the number of elements in the specified dimension of the Array. 6. GetValue :Returns the element at the specified position in an array. For example the following statement prints element at second index Console.WriteLine(a.GetValue(2)); 7. SetValue :Sets the specified value at the specified position. for example the following statement sets the value 30 at the position 3. a.SetValue(30,3); 8. Reverse : Reverses the order of the elements in a one-dimensional. This is static method and takes one parameter of Array type which has to be reversed. Ravikiran

3.18. STRING MANIPULATION IN C#

73

9. Sort : Sorts the elements in one-dimensional Array objects. This is static method and takes one parameter of Array type which has to be sorted.

3.18

String Manipulation in C#

A string is a sequential collection of Unicode characters, typically used to represent text, while a String is a sequential collection of System.Char objects that represents a string. The value of the String is the content of the sequential collection, and the value is immutable. 1. It is a reference type. 2. It’s immutable because its value cannot be modified once it has been created. Methods that appear to modify a String actually return a new String containing the modification.

3.18.1

String Manipulation Methods

String class provides various methods to manipulate the string. Some of those are.. 1. Trim :It strips all white spaces from both the start and end of the string. string Name =” String Manipulation ”; string NewName = Name.Trim(); 2. Copy : This method simple creates a copy of an existing string. It provides the same functionality as assigning to a string directly. This is a static method. string sample = ”Ravi kiran.” string result = string.Copy(sample); //result = ”Ravi kiran.” 3. Compare : It is a static method. Compares two specified String objects and returns an integer that indicates their relationship to one another in the sort order i.e. if both strings are equal it will returns 0, else if first string is greater it will returns 1 else it will returns -1. Example string s=”ravi”; string s1=”kiran”; Console.WriteLine(string.Compare(s,s1)); //Prints 1 4. Concat : Concatenates one or more instances of String, or the String representations of the values of one or more instances of Object. Example string s=string.Concat(”ravi”,”kiran”,”kumar”);

5. Contains : Returns a boolean indicating whether the specified String object occurs within this string. Example string s=”ravi kiran”; Console.WriteLine(s.Contains(”avi”)); //Prints true; Ravikiran

74

CHAPTER 3. C# LANGUAGE FUNDAMENTALS

6. EndsWith : Determines whether the end of a String matches a specified string. Example string s=”ravi kiran”; Console.WriteLine(s.EndsWith(”an”)); //Prints true; 7. Format :Replaces each format item in a specified string with the text equivalent of a corresponding object’s value. Example Console.WriteLine(string.Format(”{0:c}”,1000)); //Prints$1,000.00; 8. IndexOf :Reports the index of the first occurrence of a String within this string. Example string s=”Ravi”; Console.WriteLine(s.IndexOf(”av”)); //Prints 1; 9. Insert :Inserts a specified instance of String at a specified index position in this instance. Example string s=”Ravi kiran”; Console.WriteLine(s.Insert(0,”Bandari ”)); //Prints Bandari Ravi kiran; 10. LastIndexOf : Reports the index position of the last occurrence of a specified Unicode character or String within this instance. 11. PadLeft :Right-aligns the characters in this instance, padding on the left with spaces or a specified Unicode character for a specified total length. Example string s=”Ravi”; Console.WriteLine(s.padLeft(20,’*’)); //Prints ****************Ravi ; 12. PadRight :Left-aligns the characters in this string, padding on the right with spaces or a specified Unicode character, for a specified total length. Example string s=”Ravi”; Console.WriteLine(s.padRight(20,’*’)); //Prints Ravi**************** ; 13. Replace :Replaces all occurrences of a specified Unicode character or String in this instance, with another specified Unicode character or String. Example string s=”Ravi kiran”; Console.WriteLine(s.Replace(”a”,’aa”)); //Prints Raavi kiraan ; 14. ToUpper : Returns a copy of this String in uppercase. 15. ToLower : Returns a copy of this String in lowercase. 16. ToCharArray : Copies the characters in this instance to a Unicode character array. Example string s=”Ravi kiran”; char[] c=s.ToCharArray(); Ravikiran

3.18. STRING MANIPULATION IN C#

75

3.18.2

System.Text.StringBuilder Class

This class represents a string-like object whose value is a mutable sequence of characters. The value is said to be mutable because it can be modified once it has been created by appending, removing, replacing, or inserting characters. The following are the some of the methods defined in the StringBuilder class 1. Append : Appends the string representation of a specified object to the end of this instance. Example StringBuilder sb=new StringBuilder(”Ravi”); sb.Append(”Kiran”); Console.WriteLine(sb); //Prints Ravi Kiran 2. Insert : Inserts the string representation of a specified object into this instance at a specified character position. Example StringBuilder sb=new StringBuilder(”Kiran”); sb.Insert(0,”Ravi”); Console.WriteLine(sb); //Prints Ravi Kiran 3. Remove : Removes the specified range of characters from this instance. Example StringBuilder sb=new StringBuilder(”Ravi Kiran”); sb.Remove(0,4); Console.WriteLine(sb); //Prints Kiran 4. Replace : Replaces all occurrences of a specified character or string in this instance with another specified character or string.

3.18.3

Escape Characters and Verbatim Strings

Certain characters in C# cant be reprsented in strings in usual way for various reasons C# supports two different solutions to this problem. The first approach is to use ’escape sequences’. For example, suppose that we want to set variable a to the value: ”Hello, How are you?” We could declare this using the following command, which contains escape sequences for the quotation marks and the line break string a = ”\”Hello World\n How are you\””; The following table gives a list of the escape sequences for the characters that can be escaped in this way:

Ravikiran

76

CHAPTER 3. C# LANGUAGE FUNDAMENTALS

Character ’ ” \ Alert Backspace Form feed New Line Carriage Return Horizontal Tab Vertical Tab null

Escape Sequence \’ \” \\ \a \b \f \n \r \t \v \0 (zero)

Table 3.2: Various Escape characters in C# The second approach is to use ’verbatim string’ literals. These are defined by enclosing the required string in the characters @” and ”. To illustrate this, to set the variable ’path’ to the following value: C:\My Documents\ we could either escape the back-slash characters string path = ”C:\\My Documents\\” or use a verbatim string thus: string path = @”C:\MyDocuments\” Usefully, strings written using the verbatim string syntax can span multiple lines, and whitespace is preserved. The only character that needs escaping is the double-quote character, the escape sequence for which is two double-quotes together. For instance, suppose that you want to set the variable ’text’ to the following value: the word ”big” contains three letters. Using the verbatim string syntax, the command would look like this: string text = @”the word ””big”” contains three letters.”

3.19

Enumerations

An enumeration is a special kind of value type limited to a restricted and unchangeable set of numerical values. By default, these numerical values are integers, but they can also be longs, bytes, etc. (any numerical value except char) as will be illustrated below. When you define an enumeration you provide literals which are then used as constants for their corresponding values. The following code shows an example of such a definition: public enum Days { Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday } Note, however, that there are no numerical values specified in the above. Instead, the numerical values are set up according to the following two rules: Ravikiran

3.19. ENUMERATIONS

77

1. For the first literal: if it is unassigned, set its value to 0. 2. For any other literal: if it is unassigned, then set its value to one greater than the value of the preceding literal. From these two rules, it can be seen that DAYS.Monday will be set to 0, and the values increased until DAYS.Sunday is set to 6. Note also how we are referring to these values - the values specified in an enumeration are static, so we have to refer to them in code using the name of the enumeration: ”DAYS.Monday” rather than just ”Monday”. Furthermore, these values are final - we can’t change their runtime value. The following code demonstrates how you can override the default setting which makes the default values integers. In this example, the enumeration values are set to bytes. public enum Days:byte { Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday } You can also override the default numerical values of any and all of the enumeration elements. In the following example, the first literal is set to value 1. The other literals are then set up according to the second rule given above, so DAYS.Sunday will end up equal to 7. public enum Days:byte { Sunday=1,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday }

3.19.1

System.Enum class

System.Enum class will provide the following static methods 1. Format :Converts the specified value of a specified enumerated type to its equivalent string representation according to the specified format It takes three paramters • enumType :The enumeration type of the value to convert. • value : The value to convert. • format : The output format to use. The valid formats are (a) ”G” or ”g” : If value is equal to a named enumerated constant, the name of that constant is returned; otherwise, the decimal equivalent of value is returned. For example, suppose the only enumerated constant is named, Red, and its value is 1. If value is specified as 1, then this format returns ”Red”. However, if value is specified as 2, this format returns ”2”. Ravikiran

78

CHAPTER 3. C# LANGUAGE FUNDAMENTALS

(b) ”X” or ”x” Represents value in hexadecimal (c) ”D” or ”d” Represents value in decimal form. Example class EnumDemo { public enum Days { sunday, monday, tuesday } static void Main(string[] args) { Days d = Days.monday; Console.WriteLine(Enum.Format(typeof(Days),d,”D”)); Console.WriteLine(Enum.Format(typeof(Days),d,”G”)); Console.WriteLine(Enum.Format(typeof(Days),d,”X”)); } } 2. GetName :Retrieves the name of the constant of the specified enumeration type that has the specified value. It takes two parameters enumType : A Type that specifies the type of the enumeration. value : A Object that contains the integral value or the name of an enumeration constant. Example Console.WriteLine(Enum.GetName(typeof(Days),d)); //Prints monday 3. GetNames :Returns a zero-based, one-dimensional String array that contains the names of the constants of the specified enumeration type. Example string str[]=Enum.GetNames(typeof(Days)); 4. GetUnderlyingType : Returns the underlying type of the specified enumeration type. 5. GetUnderlyingType : Returns the underlying type of the specified enumeration type. It takes one paratmeter of Enum Type Example Console.WriteLine(Enum.GetUnderlyingType(typeof(Days))); 6. GetValues :Returns a zero-based, one-dimensional array of the values of the constants of the specified enumeration type. Example Array a=Enum.GetValues(typeof(Days)); Ravikiran

3.19. ENUMERATIONS

79

7. IsDefined :Returns a Boolean indicating whether a constant with the specified value exists in the specified enumeration type. It takes two parameters enumType - A Type that describes an enumeration. value - The constant or value being searched for in enumType. Example Console.WriteLine(Enum.IsDefined(typeof(Days),1)); //Prints true

Ravikiran

80

CHAPTER 3. C# LANGUAGE FUNDAMENTALS

Ravikiran

Chapter 4

Object Oriented Programming using C#

4.1

Definition of C# class

A class is the core of any modern Object Oriented Programming language such as C#. A class is nothing but a user defined data type (UDT) that is composed of data (fields or attributes) and functions (methods) that act upon this data. We use Classes as a template to put the properties and functionalities or behaviors in one building block for some group of objects and after that we use that template to create the objects we need. For example, if we want to have Student object in our program, the first thing we have to do is to create a Class called Person that contains all the functionalities or behaviors and properties of any student. After creating Student class, we can use this class as a template to create as many as student objects we need. Creating object of a specific class type called ”instance of the class”. The Class : Is a building block that contains the properties and functionalities that describe some group of objects, We can create a class Student that contains: • The properties of normal student like Student ID, Student N ame, Date Of Birth, F ather N ame etc... • The functionalities or behaviors of any normal student like Get M arks, Calculate Average etc... When we declare a variable in a class we call it member variables or instance variables. The name instance come from the fact that when we create an object we instance a class to create that object so instance of a class means object of that class and instance variable means variable that exists in that class. 81

82

CHAPTER 4. OBJECT ORIENTED PROGRAMMING USING C#

4.1.1

Constructors

A class will also contains Constructors which will be automatically executed when an object of a class is created. Constructors can be considered as a special class member functions that provide a simple way to create an instance of a class with inital look and feel (.i.e. all the variables in a class will be initialized to their default values when object is created). If we didnt declare any constructor in a class, the compiler will provide one default constructor(Constructor with no parameters). The role of default constructor is to ensure that all the data in a class is set to an initial safe (default) value. For Example using System; class Student { string name,sid; int markstotal; Student(string na,string id,int marks) { name=na; sid=id; markstotal=marks; } void setStudent(string na,string id,int marks) { name=na; sid=id; markstotal=marks; } void displayData(string na,string id,int marks) { name=na; sid=id; markstotal=marks; } } In the above example there is no default constructor. So, if we want to create an object for the above class, it is cumpolsory that we have to pass arguments the arguments to an object. Example Student s=new Student(”Ravi”,”std01”,100); //Calling Parameterized Constructor Student s1=new Student(); //Error - As there is no Default Constructor

Ravikiran

4.2. SELF REFERENCE IN C#

83

As there is parameterized constructor, the compiler will not include any default constructor. So in order to make above statement correct we have to explicitly include the follwoing default constructor. Student() { }

4.2

Self Reference in C#

The this keyword refers to the current instance of the class. The following are common uses of this: 1. To qualify members hidden by similar names, for example: public Employee(string name, string alias) { this.name = name; this.alias = alias; } 2. To pass an object as a parameter to other methods, for example: void display(this); It is an error to refer to this in a static method because they exist at the class level and not as part of an object.

4.2.1

Forwarding Constructor Calls using ”this”

Another use of C# ”this” keyword is to force one constructor to call another during the time of object initialization. class Student { string sid; int marks; Student(string s, int i) { sid = s; ¿ marks = i; } Student():this(”Ravi kiran”, 100) { } void display() Ravikiran

84

CHAPTER 4. OBJECT ORIENTED PROGRAMMING USING C#

{ Console.WriteLine(”Student ID {0 } /Marks {1 }”, sid, marks); } static void Main(string[] args) { Student s = new Student(); s.display(); } } Output Student ID Ravi kiran Marks 100

4.3

Default Public Interface

Once the variables and methods (including constructor) are defined in a class, the next step is define which of these memebers are directly accessible from an object variable. And these class members which are accessible from an object variable are called Public Interfaces of a class. The public interface is any item declared in a class using ”public” keyword. In C#, the default interface of a class may be populated by any of the following members. 1. Methods : These are member functions that provide some behavior to a class in which they are declared. 2. Properties : These are Accessor and Mutator Functions which are used to access or set the values to the class fields. 3. Public fields or Public Variables :These are the fields declared in a class as public. (Declaring public variables in a class is not recommended) By default, if we do not explicitly mark the visibility level of a class, it is implicitly set to ”internal”. Internal classes can only be created by types which are present within the same assembly, and are not accessible from outside the assembly.

4.4

Pillars of OOP

C# is an Object oriented Programming language. So like all Object oriented languages, C# will also supports following Object Oriented Principles.. 1. Encapsulation 2. Inheritance 3. Polymorphism Ravikiran

4.4. PILLARS OF OOP

85

4.4.1

Encapsulation

Encapsulation is the procedure of covering up of data and functions into a single unit (called class). An encapsulated object is often called an abstract data type. 1. Encapsulation is one of the fundamental principles of object-oriented programming. 2. Encapsulation is a process of hiding all the internal details of an object from the outside world 3. Encapsulation is the ability to hide its data and methods from outside the world and only expose data and methods that are required 4. Encapsulation provides a way to protect data from accidental corruption 5. Encapsulation gives you the ability to validate the values before the object user change or obtain the value 6. Encapsulation makes implementation inaccessible to other parts of the program and protect from whatever actions might be taken outside the function or class. Need for Encapsulation The need of encapsulation is to protect or prevent the code (data) from accidental corruption. In Object oriented programming data is treated as a critical element in the program development and data is packed closely to the functions that operate on it and protects it from accidental modification from outside functions. Rather than defining the data in the form of public, we can declare those fields as private. The Private data are manipulated indirectly by two ways. The first method is using a pair of conventional accessor and mutator methods. Another method is using a named property.

Ravikiran

86

CHAPTER 4. OBJECT ORIENTED PROGRAMMING USING C#

ENCAPSULATION USING ACCESSORS AND MUTATORS :

Figure 4.1: Example for Accessors and Mutators In this example employeeid and salary is private fields and providing access to the fields using public methods (SetEmployeeID,GetEmployeeID,SetSalary,GetSalary) ENCAPSULATION USING PROPERTIES : Properties are a new language feature introduced with C#. Properties in C# helps in protect a field in a class by reading and writing to it. The first method itself is good but Encapsulation can be accomplished much smoother with properties. Now let’s see an example. public class Department { private string departname; public string Departname { get { return departname; } set { departname=value; } } } Ravikiran

4.4. PILLARS OF OOP

87

public class Departmentmain { public static int Main(string[] args) { Department d= new Department(); d.departname=”Master of Computer Application”; Console.WriteLine(”The Department is : {0 }”,d.Departname); return 0; } } From the above example we see the usage of Encapsulation by using properties. The property has two accessor get and set. The get accessor returns the value of the some property field. The set accessor sets the value of the some property field with the contents of ”value”. The C# ”value” keyword represents the right hand side of the assignment. Like all the things in C# ”value” is also object. However, the underlying type of the object depends on which sort of data it represents. Internal Reprsentation of C# Properties Many programmers tend to design traditional accessor and mutator methods using ”get ” and ”set ” prefixes (e.g., get Name() and set Name()). This naming convention itself is not problematic. However, it is important to understand that C# property is internally represented using these same prefixes. For example Assume that class Employee type has a private member variable named empSSn to represent an individual’s Social Security Number, which is manipulated by a property named SSN. public class Department { private string empSSN; public string SSN { get { return empSSN; } set { empSSN=value; } } public string get SSN() { return empSSN;} //ERROR public void set SSN(string val) { empSSN = val;} //ERROR } In the above example there is one property by name SSN. This property internally represented as get SSN() and set SSN() methods. So, the compiler will generates an error if we explicitly Ravikiran

88

CHAPTER 4. OBJECT ORIENTED PROGRAMMING USING C#

include those methods in a class. Read-Only and Write-Only Properties Properties can be made read-only. This is accomplished by having only a get accessor in the property implementation. For Example... public class Department { private string empSSN; public string SSN { get { return empSSN; } } } In the above example, the property ”SSN” is having only get accessor but not set mutator. So we can call SSN as a ”read-only property Creating a Write-Only Property You can assign values to, but not read from, a write-only property. A write-only property only has a set accessor. public class Department { private string empSSN; public string SSN { set { empSSN=value; } } }

4.5

Inheritance

Inheritance is one of the primary concepts of object-oriented programming. It allows you to reuse existing code. The relationship between two or more classes is termed as Inheritance in an Object Oriented Programming language. Normally there will be one class, from which the other classes may derive. The former class is called as Base class or super class and latter class is called as derived class. All variables and methods in the base class can be called in the derived classes, provided they are declared public or protected. Ravikiran

4.5. INHERITANCE

89

The subclass can add methods and properties or modify the functionality that it has inherited to provide a more specialised version of the base class. Inheritance comes in two flavors • classical inheritance (the ”is-a” relationship) • containment/delegation model (the ”has-a” relationship).

4.5.1

Classical Inheritance :

When we establish ”is-a” relationships between classes, we are building a dependency between types. The basic idea behind classical inheritance is that new classes may extend the functionality of other classes. To illustrate, assume that we wish to define two additional classes to model sales people and managers. The hierarchy looks like this From the above figure we notice that

Figure 4.2: Employee Hierarchy sales-person ”is-a” Employee. In classical Inheritance model, base classes are used to define general characteristics that are common to all subclasses. In C#, classes are extended by means of ”:” operator. Example using System; public class ParentClass { public ParentClass() { Console.WriteLine(”Parent Constructor.”); } public void print() { Console.WriteLine(”I’m a Parent Class.”); } } public class ChildClass : ParentClass { public ChildClass() { Ravikiran

90

CHAPTER 4. OBJECT ORIENTED PROGRAMMING USING C#

Console.WriteLine(”Child Constructor.”); } public static void Main() { ChildClass child = new ChildClass(); child.print(); } } Output : Parent Constructor. Child Constructor. I’m a Parent Class.

4.5.2

Containment / Delegation model (”Has-A” Relationship)

The composition (HAS-A) relationship specifies how one class (the whole) is made up of other classes (the parts). For Example... public class Engine { public void Start() { System.Console.WriteLine(”Engine started”); } } public class Car { public string make; public Engine engine; //Car has an Engine public void Start() { engine.Start(); } }

4.5.3

”base”- keyword

The base keyword is used to access members of the base class from within a derived class: 1. Call a method on the base class that has been overridden by another method. 2. Specify which base-class constructor should be called when creating instances of the derived class. Ravikiran

4.5. INHERITANCE

91

It is an error to use the base keyword from within a static method.

using System; class BaseClass { public int i; public BaseClass(int i) { this.i = i; } } class DerivedClass:BaseClass { new int i = 0; DerivedClass(int i):base(i) { this.i = 100; } void display() { Console.WriteLine(”Value of Base Class I is {0 }”,base.i); Console.WriteLine(”Value of Derived Class I is {0 }”,i); } static void Main(string[] args) { DerivedClass dc = new DerivedClass(10); dc.display(); } } Output Value of Base Class I is 10 Value of Derived Class I is 100

Because classes cannot inherit constructors, a derived class must implement its own constructor and can only make use of the constructor of its base class by calling it explicitly. If the base class has an accessible default constructor, the derived constructor is not required to invoke the base constructor explicitly; instead, the default constructor is called implicitly as the object is constructed. However, if the base class does not have a default constructor, every derived constructor must explicitly invoke one of the base class constructors using the ”base” keyword. The keyword - ”base” identifies the base class for the current object. Ravikiran

92

CHAPTER 4. OBJECT ORIENTED PROGRAMMING USING C#

4.5.4

Preventing Inheritance : Sealed classes

When a base class is declared with sealed keyword, then that class cannot be extended. The sealed modifier is used to prevent derivation from a class. An error occurs if a sealed class is specified as the base class of another class. In C# structs are implicitly sealed; therefore, they cannot be inherited. Example for Sealed Classes using System; sealed class MyClass { public int x; } class MainClass { public static void Main() { MyClass mC = new MyClass(); mC.x = 110; Console.WriteLine(”x = {0} ”, mC.x,); }} In the preceding example, if we attempt to inherit from the sealed class by using a statement like this: class MainClass: MyClass {} //Error You will get the error message: ’MainClass’ cannot inherit from sealed class ’MyClass’. Sealed Methods in C# In C# a method can’t be declared as sealed. However when we override a method in a derived class, we can declare the overrided method as sealed as shown below. By declaring it as sealed, we can avoid further overriding of this method. Example for Sealed Method using System; sealed class MyClass { public void virtual Display() { Console.WriteLine(”Virtual Method”); } } Ravikiran

4.6. PLOYMORPHISM

93

class MainClass : MyClass { public override sealed void Display() { Console.WriteLine(”sealed method”); } public static void Main() { MainClass mC = new MainClass(); mc.Display(); } }

4.6

Ploymorphism

Through inheritance, a class can be used as more than one type; it can be used as its own type, any base types, or any interface type if it implements interfaces. This is called polymorphism. In C#, every type is polymorphic. Types can be used as their own type or as a Object instance, because any type automatically treats Object as a base type. When a derived class inherits from a base class, it gains all the methods, fields, properties and events of the base class. To change the data and behavior of a base class, we have two choices: we can replace the base member with a new derived member, or we can override a virtual base member. Replacing a member of a base class with a new derived member requires the new keyword. If a base class defines a method, field, or property, the new keyword is used to create a new definition of that method, field, or property on a derived class. The new keyword is placed before the return type of a class member that is being replaced. For example public class BaseClass { public void display() { Console.WriteLine(”Base Class”); } } public class DerivedClass : BaseClass { public new void display() { Console.WriteLine(”Derived Class”); } Ravikiran

94

CHAPTER 4. OBJECT ORIENTED PROGRAMMING USING C#

static void Main(String[] args) { BaseClass b=new DerivedClass(); b.display(); //Prints Base Class DerivedClas d=new DerivedClasb(); d.display(); //Prints Derived Class } } When the new keyword is used, the new class members are called instead of the base class members that have been replaced. Those base class members are called hidden members. Hidden class members can still be called if an instance of the derived class is cast to an instance of the base class.

static void Main(String[] args) { DerivedClas d=new DerivedClasb(); d.display(); //Prints Derived Class BaseClass b=(BaseClass)d; b.display(); } In order for an instance of a derived class to completely take over a class member from a base class, the base class has to declare that member as virtual. This is accomplished by adding the virtual keyword before the return type of the member. A derived class then has the option of using the override keyword, instead of new, to replace the base class implementation with its own. public class BaseClass { public virtual void display() { Console.WriteLine(”Base Class”); } } public class DerivedClass : BaseClass { public override void display() { Console.WriteLine(”Derived Class”); } static void Main(String[] args) Ravikiran

4.7. ABSTRACT CLASSES & ABSTRACT METHODS

95

{ DerivedClas d=new DerivedClasb(); d.display(); //Prints Derived Class BaseClass b=(BaseClass)d; //Prints Derived Class b.display(); } }

Fields cannot be virtual; only methods, properties, events and indexers can be virtual. When a derived class overrides a virtual member, that member is called even when an instance of that class is being accessed as an instance of the base class.

4.7

Abstract Classes & Abstract Methods

The abstract keyword enables us to create classes and class members that are incomplete and must be implemented in a derived class. Classes can be declared as abstract by putting the keyword abstract before the class definition. For example: public abstract class Shape { //Class Definition } An abstract class cannot be instantiated. The purpose of an abstract class is to provide a common definition of a base class that multiple derived classes can share. Abstract classes normally contain one or more abstract methods or abstract properties, such methods or properties do not provide implementations, but derived classes must override inherited abstract methods or properties. Abstract classes may also define abstract methods. This is accomplished by adding the keyword abstract before the return type of the method. For example: public abstract class Shape { public abstract void Draw(); } Abstract methods have no implementation, so the method definition is followed by a semicolon instead of a normal method block. Derived classes of the abstract class must implement all abstract methods.

Ravikiran

96

CHAPTER 4. OBJECT ORIENTED PROGRAMMING USING C#

4.8

Type Casting in C#

The first law of casting between class types is that when two classes are related by an ”isa” relationship, it is always safe to reference a derived class using a base class reference. For example a base class named Employee and a derived class named Manager, the following code works because there’s always an implied upcast from a derived class to its base class: public class Employee { } public class Manager : Employee { static void Main(String[] args) { Employee e=new Manager(); } }

However, the following is illegal, because the compiler cannot provide an implicit downcast: Manager m=new Employee() //ERROR However, we cannot cast an object of base class down to an object of type derived class because there’s no guarantee that the object supports the interface defined by the derived class. Therefore, in the case of a downcast, an explicit cast is used as follows: Manager m=(Manager)new Employee()

4.8.1

”is” - Operator

The is operator is used to check whether the run-time type of an object is compatible with a given type. he is operator cannot be overloaded. The ”is” operator is used in an expression of the form expression is type where 1. expression :An expression of a reference type. An is expression evaluates to true if both of the following conditions are met. Expressions should not be null 2. type : A type. The ”is” operator checks whether an object is compatible with a given type, and the result of the evaluation is a Boolean: true or false. The is operator will never throw an exception. The follwoing code demonstrates Ravikiran

4.8. TYPE CASTING IN C#

97

System.Object o = new System.Object(); bool b1 = (o is System.Object); //b1 is true. bool b2 = (o is Employee); //b2 is false. If the object reference is null, the is operator always returns false because there is no object available to check its type.

4.8.2

”as” - operator

Objects can be converted from one type to another, assuming that the types are compatible. Often this is achieved using implicit conversion or explicitly with the cast operator. An alternative to this is the use of the ”as” operator Implicit casting occurs if the target variable is of a compatible type that is higher in the inheritance hierarchy (a superclass), or is of an interface that is implemented by the object’s class, either directly or indirectly. In these cases, no additional work is required of the developer; the conversion happens automatically. Explicit casting must be used when the conversion is in the opposite direction to that required by implicit casting. For example, when casting an object to one of its subclasses or casting from an interface to a class. To perform explicit casting, the cast operator is used. In the following example code, we can see a variable being cast from a subclass to its superclass using implicit casting. It is then returned to the subclass using explicit casting. public class Employee { } public class Manager : Employee { static void Main(String[] args) { Manager m=new Manager(); Employee e=m; //Implicit Cast Manager m1= (Manager) e; //Explict Cast } }

Explicit casting is useful but can be problematic when the variable being cast is not compatible with the target type. In this situation an exception is thrown. C# includes another method of performing explicit conversions. Using the ”as” operator, an object can be converted from one type to another. Unlike with explicit casting, if the conversion is not possible because the types are incompatible the operation does not throw an exception. Ravikiran

98

CHAPTER 4. OBJECT ORIENTED PROGRAMMING USING C#

Instead, the resultant variable simply contains null. Example class Student { void display() { Console.WriteLine(”This is Student Class”); } static void Main(string[] args) { Object o=new Object(); Student s=(Student) o; //ERROR - Invalid Cast, generates Compile Error Student s1=o as Student; //VALID statement but here s1 will be assigned to null } }

Ravikiran

Chapter 5

Exceptions and Object Lifetime

5.1

Introduction to Errors, Bugs, and Exceptions

Writing a software is a complex process, so it is quite common for even the best software to ship with various problems. These problems may be caused either due to ”bad code”(such as overflowing the bounds of an array) or due to invalid input given by the end-user. When such an error occurs, our software may not work as expected. In software terminology, we will frequently come across these following terms • Bugs : A software bug is the common term used to describe an error, flaw, mistake, failure, or fault in a computer program or system that produces an incorrect or unexpected result, or causes it to behave in unintended ways. • Errors : Unlike bugs, errors are typically caused by the end user of the application, rather than those who created the appliation. For example, User may enter character data where numeric data is expected • Exceptions : Exception is a strange behavior of software during runtime. It is very difficult to prevent exceptions. For example Exceptions my arise either if we try to connect to a database which is not there, or if we try to open a corrupted file etc... The programmer has little control over these ”exceptional” circumstances.

5.2

The Role of .NET Exception Handling

Before .NET, many programmers used to code their own error handling logic within the context of a given application. For example, they may define a set of numerical constants that represent known error conditions and make use of them as method return values. For example

99

100

CHAPTER 5. EXCEPTIONS AND OBJECT LIFETIME

#define DIVIDE BY ZERO -3 int SomeFunction(int a, int b) { if (b == 0) // can’t divide by 0 return DIVIDE BY ZERO; return a / b; } This way of error handling is called as a classic C approach and it doesn’t provide any helpful information regarding how to deal with the problem. So there must be some way to wrap the name, message, and other helpful information regarding this error condition into single well defined package. This technique of bundling all information regarding the error is called as structured exception handling. Exception handling is an in built mechanism in .NET framework to detect and handle run time errors which can be caused due to logic or system errors. If a user (programmer) do not provide a mechanism to handle these anomalies, the .NET run time environment provide a default mechanism, which terminates the program execution. Another important feature of Exceptions in .NET is that rather than using of numeric constants for identifying the problem, we are using the exceptions as objects that contain human readable description of the problem as well as the detailed infromration of the call stack that triggered the exception in the first place.

5.2.1

The Elements of .NET Exception Handling

Programming with structured exception handling involves the following elements • 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(try block) on the callers side that invokes the exception-prone member • A block of code on the callers side that will process (or catch) the exception should it occur

Ravikiran

5.3. THE SYSTEM.EXCEPTION BASE CLASS

101

5.3

The System.Exception Base Class

System.Exception class represents an error that occurs during runtime of an application. This class is the base class for all exceptions. When an error occurs, either the system or the currently executing application reports it by throwing an exception containing information about the error. Once thrown, an exception is handled by the application or by the default exception handler.

5.3.1

Members of System.Exception Class

1. Properties • HelpLink : Gets or sets a link to the help file associated with this exception. This property returns a URL to a help file describing the error in full detail. For example, the HelpLink value could be: ”file:///C:/Ravi/help.html” • Innter Exception : This read-only property can be used to obtain information about the previous exception(s) that caused the current exception to occur. The previous exception(s) are recorded by passing them into the constructor of the most current exception. For Example try { throw new ApplicationException(”This is Application Error”); } catch (Exception e) { throw new DivideByZeroException(”This is Divide By Zero”,e); } • Message :This read-only property returns the textual description of a given error. The value of the Message property is included in the information returned by ToString. The Message property is set only when creating an Exception. If no message was supplied to the constructor for the current instance, the system supplies a default message that is formatted using the current system culture. For Example catch (Exception e) { Console.WriteLine(e.Message); } • Source :This property returns the name of the assembly that threw the exception. • StackTrace :This read-only property contains a string that identifies the sequence of calls that triggered the exception. This property is very helpful at the time of debugging. The execution stack keeps track of all the methods that are in execution at a given Ravikiran

102

CHAPTER 5. EXCEPTIONS AND OBJECT LIFETIME

instant. A trace of the method calls is called a stack trace. The stack trace listing provides a means to follow the call sequence to the line number in the method where the exception occurs. • TargetSite :This read-only property returns a MethodBase type, which describes numerous details about the method that threw the exception

5.4

Throwing a Generic Exception

When developing a software for .NET framework, it is important that exceptions are thrown only when an unexpected or invalid activity occurs that prevents a method from completing its normal function. Before throwing an exception, it is always up to us to decide excatly what constitutes the error and also when it has be thrown. When an error condition is encountered, the throw command is used to raise an exception. The throw command’s syntax is as follows: throw exceptionObj The exceptionObj is an exception object containing the details of the exception to be raised. This can be declared as an object and initialised before the throw command. However, it is more usual to create a new exception object within the throw statement, using the new keyword and one of the exception’s constructors to set the object’s properties. The following example uses a console application that requires at least one command line argument in order to execute. If no command-line argument is provided, an Exception is thrown. The constructor of System.Exception class used in the example requires a single string parameter containing the error message for the exception. class ExceptionDemo { static void Main(string[] args) { // Check that a parameter was provided if (args.Length == 0) { throw new Exception(”Invalid Arguments”); } Console.WriteLine(”{0} argument(s) provided”, args.Length); } } When executed correctly with a parameter, the above program runs without error and outputs the number of parameters detected. However, if the number of arguments used is zero, this is identified by the if statement and an exception is thrown. This avoids unexpected exceptions occurring later due to the parameters being invalid. Ravikiran

5.5. CATCING EXCEPTIONS

103

5.5

Catcing Exceptions

When we suspect that a block of code will generate an errors or throws an Exceptions, that block of code has to be included in the try-catch block. The idea behind the try and catch command is that if any anomalies happen within the try block, the catch block will be executed. For example

public class ExceptionDemo { static double Divide(int a, int b) { return a / b; } static void Main(String[] args) { Console.WriteLine(ExceptionDemo.Divide(10, 2)); } } The above example works well as long as we dont pass zero as second parameter to Exception.Divide method. But if we pass zero the program will abnormally terminate as we can’t divide by zero. The calling the ExceptionDemo.Divide method should be included in a try block as follows. try { Console.WriteLine(ExceptionDemo.Divide(10, 0)); } catch(Exception) { Console.WriteLine(e.Message); Console.WriteLine(e.Source); Console.WriteLine(e.TargetSite); } Output Attempted to divide by zero. ConsoleApplication1 Double Divide(Int32, Int32)

Even though we passed zero as second argument for ExceptionDemo.Divide Method, the program will not abnormally terminate. Instead, it will Prints the above output. Ravikiran

104

CHAPTER 5. EXCEPTIONS AND OBJECT LIFETIME

In some situations, Exceptions may also occur when we call the method that explicitly throws an Exception. For Example public class ExceptionDemo { private int age; private string yourName, childName; string YourName { set { yourName = value; } } string ChildName { set { childName = value; } } int Age { set { if (value <18) throw new Exception(”Invalid Age”); else age = value; } } public void GetData() { Console.WriteLine(”Enter Name : ”); YourName = Console.ReadLine(); try { Console.WriteLine(”Enter Name : ”); YourName = Console.ReadLine(); Console.WriteLine(”Enter Age: ”); Age = Int32.Parse(Console.ReadLine()); Console.WriteLine(”Enter {0 } Child Name”, yourName); Ravikiran

5.6. CLR SYSTEM-LEVEL EXCEPTIONS (SYSTEM.SYSTEMEXCEPTION) 05 1

ChildName = Console.ReadLine(); } catch (Exception) { Console.WriteLine(” {0 } is not having Child”, yourName); } } static void Main(String[] args) { ExceptionDemo ed = new ExceptionDemo(); ed.GetData(); } } In the above example, the Property Age is accepting the values only if we provide value greater than 18 or else Exception will be thrown. So, when ever we are accessing the Age Property, that statement should be included in the try-catch block. So, in the GetData method, if we provide value 18 then only it ask us to enter our ChildName, or else it will print Exception Message.

5.6

CLR System-Level Exceptions (System.SystemException)

Defines the base class for predefined exceptions in the System namespace. Exceptions that are thrown by methods in the base class libraries are called system exceptions. System exceptions generally derive directly from a base class named System.SystemException, which in turn derives from System.Exception. SystemException does not provide information as to the cause of the Exception. In most scenarios, instances of this class should not be thrown. In cases where this class is instantiated, a human-readable message describing the error should be passed to the constructor SystemException type does not add any additional functionality beyond that of System.Exception, The idea is that when an exception type derives from System.SystemException, we are able to determine that the .NET runtime is the entity that has thrown the exception, rather than the custom code base of the executing application.

5.7

Custom Application-Level Exceptions

ApplicationException is thrown by a user program, not by the common language runtime. If you are designing an application that needs to create its own exceptions, derive from the ApplicationException class. ApplicationException extends Exception, but does not add new functionality. When we handle an exception deriving from System.ApplicationException, we can assume that exception is raised by the code base of the executing application, rather than by the .NET Ravikiran

106

CHAPTER 5. EXCEPTIONS AND OBJECT LIFETIME

base class libraries.

5.7.1

Creating Custom Exceptions

Although the .NET framework contains all kinds of exception types which are sufficient in most cases, it can make sense to define custom exceptions in your own applications. They can greatly simplify and improve the error handling and thus increase the overall code quality. Any custom exception we create needs to derive from the System.Exception class. You can either derive directly from it or use an intermediate exception like SystemException or ApplicationException as base class. According to the .NET framework documentation, SystemException is meant only for those exceptions defined by the common language runtime whereas ApplicationException is intended to be used by user code. The absolute minimum a new custom exception class needs to have is a name. Lets say we are designing the login mechanism for a database application and as part of this job we need to create a custom exception which is thrown if a login attempt fails. A good name for such an exception would be LoginFailedException. An absolute minimum implementation in C# then looks like: public class LoginFailedException: System.Exception { } All we need to do is to create a basic custom exception which is derived from the Exception class. Theres only one problem with this definition. Since C# unfortunately doesnt inherit constructors of base classes, this new type only has the standard constructor with no parameters and is therefore relatively useless. So, we need to add at least one constructor which does something useful... public class LoginFailedException: System.Exception { // The default constructor needs to be defined // explicitly now since it would be gone otherwise. public LoginFailedException() { } public LoginFailedException(string message): base(message) { } } Now we can use our custom exception like most other exceptions. We can throw an instance of LoginFailedException and pass a message which describes the occurred error. Ravikiran

5.8. HANDLING MULTIPLE EXCEPTIONS

107

But .NET exceptions can do more. we can normally pass a so called inner exception to one of the constructors which indicates that the created exception is a direct result of a previous one. This inner exception can then be retrieved via the InnerException property. This way we can build entire exceptions chains. Since this can be quite useful sometimes, we extend our existing implementation with this additional constructor. public class LoginFailedException: System.Exception { // The default constructor needs to be defined // explicitly now since it would be gone otherwise. public LoginFailedException() { } public LoginFailedException(string message): base(message) { } public LoginFailedException(string message, Exception innerException): base(message, innerException) { } }

5.8

Handling Multiple Exceptions

A catch block can specify an exception type which it has to catch. This type is called an exception filter, and must either be the Exception type, or derived from this type While using multiple catch blocks, each catch block is checked in turn to see if the exception thrown is the same type as, or derives from, that declared in the catch statement. When a match is found, the code within the catch block is executed. Only one catch block’s code is ever executed. Exceptions thrown that do not match any of the declared types remain unhandled. For Example public class ExceptionDemo { static void Main(String[] args) { try { Console.WriteLine(”Enter A Value”); int a = Int32.Parse(Console.ReadLine()); Console.WriteLine(”Enter B Value”); int b = Int32.Parse(Console.ReadLine()); Ravikiran

108

CHAPTER 5. EXCEPTIONS AND OBJECT LIFETIME

float c = (float)a / b; Console.WriteLine(” {0} Divided By {1} is {2}”, a, b, c); } catch (DivideByZeroException ) { Console.WriteLine(”You cant Divide a number with Zero”); } catch (FormatException) { Console.WriteLine(”You have Entered an Invalid Number”); } catch (Exception ) { Console.WriteLine(”Unknown Error”); } } } Above example includes three catch blocks. The first handles any division by zero error. The second responds when we enter non numeric string instead on numeric characters. The final catch block does not specify the type of exception to catch and therefore is executed when any other type of exception occurs.

5.9

The Finally Block

C# defines an addition block that may be added to the end of the try-catch block. This is known as the finally block. The code within this section is guaranteed to be executed after the try-catch block, even if any of the statements in the try / catch block caused the current method to exit normally or by throwing a further exception. static void Main(string[] args) { int value = 50; int divisor = 0; int calculated; try { calculated = value / divisor; } catch { Console.WriteLine(”An error occurred during division.”); Ravikiran

5.10. LAST CHANCE OF EXCEPTION

109

calculated = int.MaxValue; } finally { Console.WriteLine(”Clearing up any resources.”); } } OUTPUT An error occurred during division. Clearing up any resources. Result = 2147483647

5.10

Last chance of Exception

Some times it is possible that, we may leave certain runtime anamolies with out handling them. The result of ignoring an exception would be highly obstructive to the end user of our application, as an ”unhandled exception” is displayed.

5.11

Identifing Application and System Exceptions

We can generalize our catch blocks in such a way that all our application level exceptions are handled separately from possible system-level exceptions.

try { } catch(ApplicationException) { // All Custom Applications will be caught here } catch(SystemException) { // All the exceptions thrown by CLR will be caught here }

Ravikiran

110

CHAPTER 5. EXCEPTIONS AND OBJECT LIFETIME

5.12

Debugging Unhandled Exceptions using Visual Studio

Visual Studio 2005 provides us number of tools that help to debug unhandled exceptions. When we start debugging our program in visual studio, Visual studio will automatically breaks at the time the uncaught exception is thrown.

Figure 5.1: Debugging unhandled exceptions with visual studio if we click the ViewDetail link, we will find the details regarding the state of the object

Ravikiran

5.13. UNDERSTANDING OBJECT LIFE TIME

111

5.13

Understanding Object Life Time

In .NET, objects are allocated onto a region of memory termed as the ”manged heap”, where they will be automatically deallocated by the runtime whenever an object is no longer needed. Once the object is allocated onto the managed heap, entire care will be taken by the CLR about that object. Runtime will removes an object from the heap when it is unreachable by the current application. For example public class ObjectDemo { public void display() { Console.WriteLine(”This is ObjectDemo Class”); } } public class ObjectLifeTime { void Display() { ObjectDemo od = new ObjectDemo(); od.display(); } public static void main(string[] args) { { ObjectLifeTime o = new ObjectLifeTime(); o.Display(); } o.Display(); // ERROR - Object o has gone out of scope, so // it is subjected for Garbage Collection. ObjectLifeTime o1 = new ObjectLifeTime(); o1.Display(); } // HERE object o1 also gone for out of scope, object o1 can be now removed // from heap memory }

Ravikiran

112

CHAPTER 5. EXCEPTIONS AND OBJECT LIFETIME

5.14

The CIL of ”new”

When a C# compiler encounters a ’new’ keyword, it will emit CIL ”newobj” instruction to the code module. Managed heap is more than just a raw chunk of memory accessed by the CLR. The .NET garbage collector is quite a tidy housekeeper, given that i will compact empty blocks of memory(when necessary) for purpose of optimization. In this optimization process, the managed heap maintains a pointer (commonly referred to as the new object pointer) that identifies exactly where the next object will be placed on the heap itself.The newobj instruction informs the CLR to perform the following sequence of events. 1. Calculate the total amount of memory required for the object about to be allocated. If the object contains other internal objects (i.e. the ”has-a” relationship as well as nested type members), memory for those objects should also be calculated. Also the memory required for each base class is also taken into account. 2. The CLR then examines the managed heap to ensure that there is enough memory to allocate for the object to be newly created. If there is enough memory, the type’s constructor is called, and the caller is returned a reference to the type in the memory, which just happens to be identical to the last position of the new object pointer. 3. Finally, before returning the reference to the caller, the CLR will advance the new object pointer to point to the next available slot on the managed heap. If we goes on creating objects, at some point of time the managed heap will become full. When newobj instruction is encountered, and if CLR determines that managed heap does not have sufficient memory to allocate the requested type, it will perform a garbage collection in an attempt to free up memory. Garbage Collector in .Net is in deterministic which means that we can never be sure when the garbage collector be invoked. When garbage collection occurs, the runtime will checks for objects in the managed heap that are no longer being used by the application and performs the necessary operations to reclaim their memory.

5.15

Garbage Collection Algorithm

Application Roots Every application has a set of roots. Roots identify storage locations, which refer to objects on the managed heap or to objects that are set to null. For example 1. References to global objects 2. Reference to any static objects / static fields 3. Reference to local objects within an applications code base Ravikiran

5.15. GARBAGE COLLECTION ALGORITHM

113

4. Reference to object parameters passed into a method 5. Any CPU register that references an object Implementation Garbage collection in .NET is done using tracing collection and specifically the CLR implements the Mark/Compact collector. This method consists of two phases as described below. • Phase:1 Mark Find memory that can be reclaimed. When the garbage collector starts running, it makes the assumption that all objects in the heap are garbage. In other words, it assumes that none of the application’s roots refer to any objects in the heap. The following steps are included in Phase 1: 1. The GC identifies live object references or application roots. 2. It starts walking the roots and building a graph of all objects reachable from the roots 3. If the GC attempts to add an object already present in the graph, then it stops walking down that path. This serves two purposes. First, it helps performance significantly since it doesn’t walk through a set of objects more than once. Second, it prevents infinite loops should you have any circular linked lists of objects. Once all the roots have been checked, the garbage collector’s graph contains the set of all objects that are somehow reachable from the application’s roots; any objects that are not in the graph are not accessible by the application, and are therefore considered garbage. • Phase II: Compact Move all the live objects to the bottom of the heap, leaving free space at the top. Phase II includes the following steps: 1. The garbage collector now walks through the heap linearly, looking for contiguous blocks of garbage objects 2. The garbage collector then shifts the non-garbage objects down in memory, removing all of the gaps in the heap 3. Moving the objects in memory invalidates all pointers to the objects. So the garbage collector modifies the application’s roots so that the pointers point to the objects’ new locations 4. In addition, if any object contains a pointer to another object, the garbage collector is responsible for correcting these pointers as well. 5. After all the garbage has been identified, all the non-garbage has been compacted, and all the non-garbage pointers have been fixed-up, a pointer is positioned just after the last non-garbage object to indicate the position where the next object can be added. Ravikiran

114

CHAPTER 5. EXCEPTIONS AND OBJECT LIFETIME

5.16

Finializing a Type

.NET garbage collection scheme is non-deterministic in nature, i.e. it is difficult to determine excatly when an object will be deallocated from the memory..NET automatic memory management is quite helpful to us if we do not included any unmanaged code into our application. But some times there may be a need to include unmanged objects for which automatic memory management is not done i.e. we have to explicitly remove those unmanaged objects from the memory. To account for such situations, one choice we have is to override the virtual System.Object.Finalize() method (the default implementation does nothing). But the odd thing is C# language does not allow us to directly override the finalize method using the following standard syntax public class Student { protected override void Finailize() // ERROR - Overriding Finialize is not allowed { } } Instead of overrding the Finalize method, we have to make use of (C++ like) destructor to syntax to achieve the same effect. public class Student { ∼ Student() { } }

5.17

The Finalization Process

The role of a finalizer is to ensure that a .NET object can clean up unmanaged resources. Thus, if we are building a type that does not make use of unmanaged entities, finalization is of little use. When we place an object onto the managed heap using the new operator, the runtime automatically determines if our object supports a custom Finalize() method. If so, the object is marked as finalizable, and a pointer to this object is stored on an internal queue called finalization queue. The finalization queue is a table maintained by the CLR that points to each and every object that must be finalized before it is removed from the heap. When the garbage collector determines it is time to free an object from memory, it examines each entry cataloged on the finalization queue, and copies the object off the heap to yet another CLRmanaged structure termed the finalization reachable table (often abbreviated as freachable, and pronounced ”Freachable”). At this point, a separate thread is spawned to invoke the Finalize() method for each object on the freachable table at the next garbage collection. Ravikiran

5.18. BUILDING AN AD HOC DESTRUCTION METHOD

115

5.18

Building an Ad Hoc Destruction Method

When our type manipulates unmanaged resources, we do need to ensure they are released in a timely and predictable manner. Even though we can do this by using destructors, still there are better ways. One alternative is to define a custom method that we can assume all objects in our system implement. Let’s call this method as Dispose(). The assumption is that when the object user is finished using our type, it manually calls Dispose() before allowing the object reference to drop out of scope. In this way, our objects can perform any amount of cleanup necessary of unmanaged resources without incurring the hit of being placed on the finalization queue and without waiting for the garbage collector to trigger the class finalization logic public class Student { public void Dispose() { /* Clean up your internal unmanaged resources. */ } }

5.18.1

The IDisposable Interface

In order to provide symmentry among all the objects that support an explicit destruction routine, the .NET class libraries define an interface named IDisposable that supports a single member named Dispose(). public Interface IDisposable { public void Dispose(); } Its a better way to follow to implement the IDisposable interface for all types that wish to support an explicit form of resource deallocation. For example public class Student:IDisposable { public void Dispose() { /* Clean up your internal unmanaged resources. */ } static void Main(string[] args) { Student s=new Student(); s.Dispose(); Ravikiran

116

CHAPTER 5. EXCEPTIONS AND OBJECT LIFETIME

} }

5.18.2

Reusing the C# ”using” Keyword

The ”using” keyword has a double meaning (specifying namespaces and triggering a Dispose() method). When we are working with .NET types that support IDisposable interface, this syntactically construct will ensure that object being used will automatically have its Dispose() Method called once the block has exited. On the other hand, if we specify a type that does not implement IDisposable within the using declaration, we will get a compile time error. public class Student:IDisposable { public void Dispose() { /* Clean up your internal unmanaged resources. */ } static void Main(string[] args) { using(Sudent s=new Student()) { /* Dispose() method is automatically when the using block exits */ } } }

5.19

Garbage Collection Optimizations

When the CLR is attempting to locate unreachable objects, is does not literally walk over each and every object placed on the managed heap looking for orphaned roots. Doing so would involve considerable time, especially in larger (i.e., real-world) applications. To help optimize the collection process, each object on the heap is assigned to a given ”generation.” The idea behind generations is simple: The longer an object has existed on the heap, the more likely it is to stay there (for example, the object implementing an application’s Main() method). Conversely, objects that have been recently placed on the heap are more likely to be dereferenced by the application rather quickly (such as an object created within a method scope). Given these assumptions, each object belongs to one of the following generations 1. Generation 0 Identifies a newly allocated object that has never been marked for collection 2. Generation 1 Identifies an object that has survied 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) Ravikiran

5.20. THE SYSTEM.GC TYPE

117

3. Generation 2 Identifies an object that has survied more than one sweep of the garbage collector. Now, when the collection occurs, the Garbage Collector marks and sweeps all generation-0 objects first. If this results in the required amount of memory, the remaining objects are promted to the next available generation. If all generation-0 objects have been removed from the heap, but more memory is still necessary, generation-1 objects are marked and swept, followed (if necessary) by generation-2 objects. In this way the newer objects (i.e. local variables) are removed quickly while an older object is assumed to be in use.

5.20

The System.GC Type

System.GC type allows us to interact with the Garbage Collector using a small set of static members. • Collect() : Forces the GC to call the Finalize() method for every object on the managed heap. • GetGeneration() : Returns the generation to which an object currently belongs. • MaxGeneration : This property returns the maximum of generations supported on the target system. • SuppressFinalize() : Sets a flag indicating that a given object should not have its Finalize() method called • ReRegisterForFinalize() : Sets a flag indicating that a suppressed object should be reregistered as finalizable. This (of course) assumes the object was marked as nonfinalizable using SuppressFinalize(). • GetTotalMemory() : Returns the estimated amount of memory (in bytes) currently being used by all the objects in the heap including the objects that are soon to be destroyed. This method takes one boolean parameter that is used to specify if a garbage collection should occur during the method invocation. Example

public class Student:IDisposable { ∼ Student() { } public void Dispose() { Ravikiran

118

CHAPTER 5. EXCEPTIONS AND OBJECT LIFETIME

/* Clean up your internal unmanaged resources. */ GC.SuppressFinalize(this); } static void Main(string[] args) { Student s= new Student(); s.Dispose(); } } In the above example, the student class is having both C++ style destructor as well as the IDisposable interface. Here, our Dispose() method has been altered to call GC.SuppressFinalize() which informs the system that it should no longer call the destructor for the specified object, as the end user has called Dispose() method.

Ravikiran

Chapter 6

Interfaces and Collections
Interfaces describe a group of related functionalities that can belong to any class or struct. Interfaces can consist of methods, properties, events, indexers, or any combination of those four member types. When a class or struct is said to inherit an interface, it means that the class or struct provides an implementation for all of the members defined by the interface. The interface itself provides no functionality that a class or struct can inherit in the way that base class functionality can be inherited. However, if a base class implements an interface, the derived class inherits that implementation. Interfaces allow you to truly separate the what from the how. The interface tells you only what the name, return type, and parameters of the method are. Exactly how the method is implemented is not a concern of the interface. The interface represents how you want an object to be used, rather than how it happens to be implemented at a particular moment in time. Interface Syntax To declare an interface, we use the interface keyword instead of the class or struct keyword. Inside the interface, we declare methods exactly as in a class or a struct, except that we never specify an access modifier (no public, private, or protected access), and we replace the method body with a semicolon. Here is an example: interface IEmployee { string Name(); } Interface Restrictions The interface never contains any implementation. The following restrictions are natural consequences of this 119

120

CHAPTER 6. INTERFACES AND COLLECTIONS

1. we are not allowed any fields in an interface, not even static ones. 2. Interfaces do not contain any constructors or even destructors. 3. We cannot supply any access modifier in interfaces. All the methods in an interface are implicitly public. 4. We cannot inherit any interface from a struct or class.

6.1

Implementing Interfaces

To implement an interface, we declare a class that inherits from the interface and implements all the interface methods. For example, suppose you are defining the Employee hierarchy shown earlier, but need to specify that all classes in the hierarchy provide a method called Name that returns the name of the current token as a string. we could define the IEmployee interface that contains this method: interface IEmployee { string Name(); } interface IEmployer { int Count(); } We could the implement these interfaces in the Manager class: class Manager : IEmployee,IEmployer { string name; int i; Manager(string s,int temp) { name=s; i=temp; } public string Name() { return name; } public int Count() { return i; Ravikiran

6.2. CONTRASTING INTERFACES TO ABSTRACT BASE CLASSES

121

} } When we implement an interface, we must ensure that each method matches its corresponding interface method exactly, according to the following guidelines: 1. The method names and return types match exactly. 2. Any parameters (including ref and out keyword modifiers, although not the params keyword modifier) match exactly. 3. If there is any difference between the interface definition and its declared implementation, the class will not compile.

6.2

Contrasting Interfaces to Abstract Base Classes

Like Interfaces, Abstract classes not only contain a group of abstract methods, but they also contain non abstract methods which have default implementation. Abstract methods 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, never define state data and never provide an implementation of the methods. In C# a class can be derived only from single base class. But, the interfaces will provide us to derive a class from multiple interfaces.

6.3

Invoking Interface Members at Object Level

The most straight forward way to interact with functionality supplied by a given interface is to invoke the methods directly from the object level. For example static void Main(string[] args) { Manager m=new Manager(”Ravi”,20); Console.WriteLine(”Name 0 Age : 1 ”,m.Name(),m.Count()); } In this approach we can come to know at the comopile time only about the interfaces that the given class is implemented. But sometimes, we will not able to determine at compile time which interfaces are supported by a given type. For example, assume that we have an array containg 50 Employe - compatable types only some of them are Employers. So if we attempt to to invoke the Count method on a type that has not implemented Employer, we will receive a compile time error. For example Ravikiran

122

CHAPTER 6. INTERFACES AND COLLECTIONS

class Manager : IEmployee,IEmployer { string name; int i; Manager(string s,int temp) { name=s; i=temp; } public string Name() { return name; } public int Count() { return i; } } class Worker : IEmployee { string name; Worker(string s) { name=s; } public string Name() { return name; } } class Company { static void Main(string[] args) { IEmployee[] e=new IEmployee[2]; e[0]=new Manager(”Ravi”,30); e[1]=new Worker(”Kumar”); Console.WriteLine(e[0].Count()); Console.WriteLine(e[1].Count());// ERROR since e[1] is not of Manager Type

Ravikiran

6.3. INVOKING INTERFACE MEMBERS AT OBJECT LEVEL

123

} } In the above example, if we try to call e[1].Count() method, we will get an error as e[1] is an object of type Worker where it will not contain the Count() method. So, in order to avoid such errors, we have to explicitly convert an object to the interface reference. For example Manager m=new Manager(”Ravi kiran”,30); IEmployer e=(IEmployer)m; // Explicit Casting Console.WriteLine(”Name : {0} \n Count : {1}”,e.Name(),e.Count());

In the above example, we are explicitly trying to convert manager class to IEmployee interface. If the object does support this interface, we are then able to access the behavior accordingly. However if we try to convert an object of type Worker into IEmployer interface reference, we will get a runtime error when invoke Count() method. When we attempt to access an interface not supported by a given class using a direct cast, the runtime throws an InvalidCastException. To recover safely from this excption, we have to catch it. For Example.. try { Worker w=new Woker(); IEmployer e=(IEmployer)w; } catch(InvalidCastException e) { Console.WriteLine(”Unable to process your request - Invalid Cast”); }

Obtaining Interface References: The ”as” Keyword The second way we can test for interface support (as well as obtain an interface from an object reference) is to make use of the ”as” keyword. For example: Workder w=new Worker(); IEmployer e=w as Worker; if(e!=null) e.Count(); There is no need of try/catch block when we are making use of the as keyword, given that if the reference is not null, we know that we are calling on a valid interface reference. Ravikiran

124

CHAPTER 6. INTERFACES AND COLLECTIONS

Obtaining Interface References: The ”is” Keyword The another way to check the implemented interface for a given type is -”is” keyword. If the object is not compatiable with the specified interface, we are returned false. On the other hand, if the type is compatible with the interface, then we can safely call the members without needing to make use of try/catch logic. For example... IEmployee[] e=new Manager(),new Worker(),new Worker(),new Worker(),new Manager(); foreach (IEmployee e in IEmployee) { if(e is IEmployer) e.Count(); } Interfaces as Parameters As Interfaces are strongly typed entities, we can use them as parameters for constructing the methods as well as we can return as values from the methods. For example interface Animal { void Move(); } class Dog : Animal { public void Move() { Console.Write(”Dog Can Move from one place to another”); } static Animal GetAnimal() { Animal a=new Dog(); return a; } } class MainClass { static void IsMoving( Animal listener ) { listener.Move(); } static void Main() { Ravikiran

6.4. EXPLICIT INTERFACE IMPLEMENTATION

125

Dog dog = new Dog(); ListenToMe( dog ); Animal anim=Dog.GetAnimal(); anim.Move(); } }

6.4

Explicit Interface Implementation

A class that implements an interface can explicitly implement a member of that interface. When a member is explicitly implemented, it cannot be accessed through a class instance, but only through an instance of the interface.

using System; interface InterfaceOne { void Execute(); } interface InterfaceTwo { void Execute(); } class MyImplementation: InterfaceOne, InterfaceTwo { void InterfaceOne.Execute() { Console.WriteLine(”InterfaceOne.Execute implementation”); } void InterfaceTwo.Execute() { Console.WriteLine(”InterfaceTwo.Execute implementation”); } } class MainClass { public static void Main() { MyImplementation myImplementation = new MyImplementation(); InterfaceOne interfaceOne = (InterfaceOne) MyImplementation; interfaceOne.Execute(); Ravikiran

126

CHAPTER 6. INTERFACES AND COLLECTIONS

InterfaceTwo interfaceTwo = (InterfaceTwo) MyImplementation; interfaceTwo.Execute(); } }

6.4.1

The Advantages of Explicit Interface Implementations

Implementing an interface explicitly offer a number of advantages that help us to write clearer, more maintainable, and more predictable code. We can implement a method without explicitly specifying the interface name, but this can lead to some differences in the way the implementation behaves. Some of these differences can cause confusion. For example, a method defined by using explicit interface implementation cannot be declared as virtual, whereas omitting the interface name allows this behavior. Explicit interface implementation disambiguates methods from different interfaces that have the same name, return type, and parameters. The methods that implement the interface are publicly accessible, but only through the interface. Without using explicit interface implementation it would not be possible to distinguish which method implements part of which interface if multiple interfaces contain methods with the same names, return types, and parameters.

6.5

Building 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 also possible to build derived relationships among interfaces. For Example interface IPerson { void GetDetails(); } interface IStudent:Person { void CalculateGrade(); } Now, if a class wished to support each behavior expressed in this interface hierarchy, it would derive from the nth-most interface (IStudent). Any methods defined by the base interface(s) are automatically carried into the definition. For example: class Student:IStudent { void GetDetails() { } Ravikiran

6.5. BUILDING INTERFACE HIERARCHIES

127

void CalculateGrade() { } }

Interfaces With Multiple Base References interface Getter { int GetData(); } interface Setter { void SetData(int x); } interface GetterAndSetter : Getter, Setter { } class MyData : GetterAndSetter { int data; public int GetData() { return data; } public void SetData(int x) { data = x; } } class MainClass { static void Main() { MyData data = new MyData(); data.SetData(5); Console.WriteLine(”0”, data.GetData()); } } We can build interface hierarchies, that derives from Other Interfaces as above Ravikiran

128

CHAPTER 6. INTERFACES AND COLLECTIONS

6.6

IConvertible Interface

Defines methods that convert the value of the implementing reference or value type to a common language runtime type that has an equivalent value. This interface provides methods to convert the value of an instance of an implementing type to a common language runtime type that has an equivalent value. The common language runtime types are Boolean, SByte, Byte, Int16, UInt16, Int32, UInt32, Int64, UInt64, Single, Double, Decimal, DateTime, Char, and String. If there is no meaningful conversion to a common language runtime type, then a particular interface method implementation throws InvalidCastException. For example, if this interface is implemented on a Boolean type, the implementation of the ToDateTime method throws an exception because there is no meaningful DateTime equivalent to a Boolean type. For example... bool myBool = true; IConvertible itfConv = (IConvertible)myBool; The following are the members of IConvertible Interface

public interface IConvertible { TypeCode GetTypeCode(); bool ToBoolean(IFormatProvider provider); byte ToByte(IFormatProvider provider); char ToChar(IFormatProvider provider); DateTime ToDateTime(IFormatProvider provider); Decimal ToDecimal(IFormatProvider provider); double ToDouble(IFormatProvider provider); short ToInt16(IFormatProvider provider); int ToInt32(IFormatProvider provider); long ToInt64(IFormatProvider provider); SByte ToSByte(IFormatProvider provider); float ToSingle(IFormatProvider provider); string ToString(IFormatProvider provider); object ToType(Type conversionType, IFormatProvider provider); UInt16 ToUInt16(IFormatProvider provider); UInt32 ToUInt32(IFormatProvider provider); UInt64 ToUInt64(IFormatProvider provider); }

Ravikiran

6.6. ICONVERTIBLE INTERFACE

129

6.6.1

The IConvertible.ToXXXX() Members

The IConvertible interface defines number of methods of the form ToXXXX(), which will provide a way to convert from one type to another. For example

bool myBool =true; IConvertible convert= (IConvertible)myBool; try { DateTime d=convert.ToDateTime(); }catch(InvalidCastException){ } IFormatProvider All the IConvertible.ToXXXX() methods takes a parameter of type IFormatProvider. Objects that implement this interface are able to format their contents based on the culture-specific information (for example, returning a floating point number that is formated in various currencies).

public interface IFormatProvider { object GetFormat(Type formatType); } If we are building custom type that should be formatted using various locals, we have to implement IFormatProvider static void Main(string[] args) { Console.WriteLine(System.Environment.CommandLine); int theInt = 13; IConvertible convert = (IConvertible)theInt; byte theByte = convert.ToByte(CultureInfo.CurrentCulture); Console.WriteLine(”Type code int converted to byte is: 0”, theByte.GetTypeCode()); Console.WriteLine(”Value of converted int: 0”, theByte); } IConvertible.GetTypeCode() This method allows us to programmatically determine a value that represents the typecode of the type which is represented by the following enumeration. public enum TypeCode Ravikiran

130

CHAPTER 6. INTERFACES AND COLLECTIONS

{ Boolean, Byte, Char, DateTime, DBNull, Decimal, Double, Empty, Int16, Int32, Int64, Object, SByte, Single, String, UInt16,UInt32, UInt64 } Example public TypeCode IConvertible.GetTypeCode() { return TypeCode.Object; }

6.7

Building Custom Enumerator

IEnumerator is the base class for all nongeneric enumerators. Enumerators can be used to read the data in the collection, but they cannot be used to modify the underlying collection. For example if we want to represent collection of individual Person objects, we can use Standard System.ArrayType. And it would be convenient to iterate over the Person type using the C# foreach construct in order to obtain each individual Person. class Person { string name; public Person(string name) { this.name = name; } public void Display() { Console.WriteLine(”Person Name : {0 }”,name); } } class People { Person[] p; People() { p = new Person[4]; p[0] = new Person(”Bandari”); p[1] = new Person(”Ravi”); p[2] = new Person(”Kiran”); p[3] = new Person(”Kumar”); } Ravikiran

6.7. BUILDING CUSTOM ENUMERATOR

131

static void Main() { People p = new People(); foreach (Person temp in p) temp.Display(); } } If we attempt to execute the above code, the compiler would complain that the People class does not implement the GetEnumerator() method. This method is defined by the IEnumerable interface. public interface IEnumerable { IEnumerator GetEnumerator(); } Thus, to rectify the problem, you may begin by updating the People definition as follows: public class People : IEnumerable { // IEnumerable defines a single method. public IEnumerator GetEnumerator() { ... } } GetEnumerator() method returns yet another interface named IEnumerator. IEnumerator can be obtained from an object to traverse over an internal collection of types. IEnumerator is also defined in the System.Collections namespace and defines the following three methods // IEnumerable.GetEnumerator returns an object implementing IEnumerator public interface IEnumerator { bool MoveNext(); // Advance the internal position of the cursor object Current{get;} // Gets the Current Item (Read only Property); void Reset(); // Reset the cursor to the begining of the cursor } Now given that IEnumerable.GetEnumerator() returns an IEnumerator, we have to update the Persons type as follows public class People : IEnumerable,IEnumerator { Ravikiran

132

CHAPTER 6. INTERFACES AND COLLECTIONS

// IEnumerable defines a single method. public IEnumerator GetEnumerator() { return (IEnumerator)this; } } Finally, we have to implement MoveNext(), Current, and Reset() for the People type. Here is one possible implementation of these members: class Person { string name; public Person(string name) { this.name = name; } public override string ToString() { return string.Format(”Person Name : {0 }”, name); } } class People:IEnumerable,IEnumerator { Person[] p; private int pos = -1; public IEnumerator GetEnumerator() { return (IEnumerator)this; } People() { p = new Person[4]; p[0] = new Person(”Bandari”); p[1] = new Person(”Ravi”); p[2] = new Person(”Kiran”); p[3] = new Person(”Kumar”); } object IEnumerator.Current { get { return p[pos]; } } Ravikiran

6.8. BUILDING CLONEABLE OBJECTS

133

bool IEnumerator.MoveNext() { if (pos <p.Length-1) { pos++; return true; } return false; } void IEnumerator.Reset() { pos = 0; } static void Main() { People p = new People(); IEnumerator ie = p.GetEnumerator(); while (ie.MoveNext()) { Person per = (Person)ie.Current; Console.WriteLine(per); } } }

6.8

Building Cloneable objects

Supports cloning, which creates a new instance of a class with the same value as an existing instance. The ICloneable interface contains one member, Clone, which is intended to support cloning. To illustrate, assume you have a simple class named Person: class Person { public string name; public int age; Person(string name, int age) { this.name = name; this.age = age; } public override string ToString() Ravikiran

134

CHAPTER 6. INTERFACES AND COLLECTIONS

{ return String.Format(”Name:{0 }\nAge:{1 }”, this.name, this.age); } static void Main() { Person p1 = new Person(”Ravi”, 28); Person p2 = p1; p1.name = ”Kiran”; Console.WriteLine(p2); } } If we assign one object to another object, only reference will be copied. So if we change the values of p1 the same will be affected on object p2. When we wish our custom types to return identical copy of itself to the caller, we have to implement the standard ICloneable interface. This type defines a single method named Clone(). public interface ICloneable { object Clone(); } The basic functionality of Clone() method is to copy the value of our member variables into a new object instance and return it to the user. class Person { public string name; public int age; Person(string name, int age) { this.name = name; this.age = age; } public override string ToString() { return String.Format(”Name: {0 }\nAge: {1 }”, this.name, this.age); } public object Clone() { return new Person(this.name,this.age); } static void Main() Ravikiran

6.9. BUILDING COMPARABLE OBJECTS (ICOMPARABLE)

135

{ Person p1 = new Person(”Ravi”, 28); Person p2 = (Person)p1.Clone(); p1.name = ”Kiran”; Console.WriteLine(p2); } } In this way, we can create exact copies of the Person type, as illustrated in the above code. If our type (here Person) did not contain any internal reference types, then we can modify the Clone() Method as follows

public object Clone() { return this.MemberWiseClone(); } MemberWiseClone() method of object class, will perfom only shallow copy i.e. it will also copy references of any Internal reference types. If we want to perfom deep copy we need to create a new instance type and manually assign the inner object reference to new (identical) objects.

6.9

Building Comparable Objects (IComparable)

The IComparable interface specifies a behavior that allows an object to be sorted based on some internal key. If we have an array of types (such as the string or the integer types) that already support IComparer, we can sort that array without providing any explicit reference to IComparer. In this case, the elements of the array are cast to the default implementation of IComparer (Comparer.Default) for us. However, if we want to sort and to compare our custom objects, we must implement either IComprable or IComprer or both of these interfaces. The IComparable interface provides a method to compare two objects of a particular type. This interface is used if we want to order our object. For example, if we have an array of objects of our type, and if you call the Sort method on that array, you can use the IComparable interface to compare the objects during the sort. When we implement the IComparable interface, you must define the CompareTo method. For example... using System; using System.Collections; class Person:IComparable { public string name; public int age; public int[] arry; Person(string name, int age) Ravikiran

136

CHAPTER 6. INTERFACES AND COLLECTIONS

{ this.name = name; this.age = age; } public override string ToString() { return String.Format(”Name: {0 }\n Age: {1 }”, this.name, this.age); } static void Main() { Person[] person = new Person[3]; person[0] = new Person(”Ravi”, 29); person[1] = new Person(”Bandari”, 28); person[2] = new Person(”Kiran”,30); foreach (Person temp in person) Console.WriteLine(temp); Array.Sort(person); Console.WriteLine(”After Sorting...”); foreach (Person temp in person) Console.WriteLine(temp); } public int CompareTo(object obj) { Person temp = (Person)obj; if (this.age <temp.age) return -1; if (this.age >temp.age) return 1; return 0; } } Now, in the above program Array.Sort(person) statement sorts the person array based on the age data member of the person.

6.9.1

Specifying Multiple Sort Order

In the above example, we are sorting based on the age of the person. But if we want to sort based on the name of the person. For this, we have to use another standard interface named IComparer which is defined in the System.Collections namespace. This interface contains only one method interface IComparer Ravikiran

6.9. BUILDING COMPARABLE OBJECTS (ICOMPARABLE)

137

{ int Compare(object obj1,object obj2); }

Unlike IComparable interface, IComparer is not implemented on the type we are trying to sort (here Person). Rather, we implement this interface on any of the helper objects one for each sort order. Currently, the Person type already knows how to compare itself against other Person type based on the age type. Therefore to allow the object Person object to sort an an array of Person types by their name will require an additional helper class that implements the IComparer interface. Here’s the code

class SortByName: IComparer { public int Compare(object obj1,object obj2) { Person p1=(Person)obj1; Person p2=(Person)obj2; return String.Compare(p1.name,p2.name); } }

System.Array has a number of overloaded Sort() methods, one that just happens to take an object implementing IComparer

static void Main() { Person[] person = new Person[3]; person[0] = new Person(”Ravi”, 29); person[1] = new Person(”Bandari”, 28); person[2] = new Person(”Kiran”,30); foreach (Person temp in person) Console.WriteLine(temp); // sorting is done based on the name Array.Sort(person, new SortByName() ); Console.WriteLine(”After Sorting...”); foreach (Person temp in person) Console.WriteLine(temp); }

Ravikiran

138

CHAPTER 6. INTERFACES AND COLLECTIONS

6.10
6.10.1

Exploring the System.Collections Namespace
The Interfaces of System.Collections

First of all, System.Collections defines a number of standard interfaces. Most of the classes defined within the System.Collections namespace implement these interfaces to provide access to their contents. The following are the some of the interfaces available in System.Collections namespace. 1. ICollection : Defines generic characteristics (eg- read-only, thread safe ) for a collection class. 2. IComparer : Allows two objects to be compared. 3. IDictonary : Allows an object to represent its content using name/value pairs 4. IDictonary Enumerator : Used to enumerate the contents of an object supporting IDictonary. 5. IEnumerable : Returns the IEnumerator interface for a given object 6. IEnumerator : Generally used to support foreach-style iteration of the sub types. 7. IHashCodeProvider : tomized hash alogrithm Returns the hash code for the Implementing type using a cus-

8. IList : Provides a behavior to add, remove, and index items in a list of objects.

6.10.2

The Role of ICollection

The ICollection interface is the most primitive interface of the System.Collections namespace. In that it defines a behavior supported by a collection type. This interface provides a small set of properties that allow us to determine • the number of items in the container • the thread-safety of the container • the ability to copy the contents into a System.Array type ICollection is defined as follows (again note that ICollection extends IEnumerable): public interface ICollection : IEnumrable { int Count{get;} bool IsSynchronized{ get; } object SyncRoot{get;} void CopyTo(Array array, int index); }

Ravikiran

6.10. EXPLORING THE SYSTEM.COLLECTIONS NAMESPACE

139

6.10.3

The Role of IDictonary

The functionality of IDictonary is obtained by its base interfaces - ICollection and IEnumerable. Here is the defintion of IDictonary public interface IDictonary : IEnumrable, ICollection { bool IsFixedSize{get;} bool IsReadOnly{get;} object this[object key]{get; set; } ICollection Keys{get;} ICollection Values{get;} void Add(object key, object value); void Clear(); bool Contains(object key); IDictonaryEnumerator GetEnumerator(); void Remove(object key); }

6.10.4

The Role of IDictionaryEnumerator

The method IDictionary.GetEnumerator() returns an instance of the IDictionaryEnumerator type. As we may be expecting, IDictionaryEnumerator is simply a strongly typed enumerator, given that it extends IEnumerator by adding the following functionality: public interface IDictionaryEnumerator : IEnumerator { DictonaryEntry Entry{get;} object Key{ get; } object Value{get;} void CopyTo(Array array, int index); } IDictonaryEnumerator allows us to enumerate over items in the dictionary via the generic Entry property, which returns a System.Collections.DictionaryEntry class type. In addition, we are also able to traverse the name/value pairs using the Key/Value properties.

6.10.5

The Role of IHashCodeProvider

This interface contains only one Interface public interface IHashCodeProvider { int GetHashCode(object obj); } Ravikiran

140

CHAPTER 6. INTERFACES AND COLLECTIONS

The types that implement this interface provides the ability to retrieve the hash code for a particular type (which may or may not leverage the type’s implementation of System.Object.GetHashCode()).

6.10.6

The Role of IList

The final key interface of System.Collections is IList, which provides the ability to insert, remove, and index items into a container. public interface IList:IEnumerable, ICollection { bool IsFixedSize{get;} bool IsReadOnly{get;} object this[int index] {get; set; } int Add(object value); void Clear(); bool Contains(object value); int IndexOf(object value); void Insert(int index,object value); void Remove(object value); void RemoveAt(int index); }

6.10.7

The Class Types of System.Collections

The following are the class types that are included in the System.Collections namespace. ArrayList ArrayList is a useful class for shuffling elements around in an array. • You can add an element to the end of an ArrayList by using its Add method. You supply the element to be added. The ArrayList resizes itself if necessary. • You can insert an element into the middle of an ArrayList by using its Insert method. Again, the ArrayList resizes itself if necessary. For example static void Main() { ArrayList array = new ArrayList(); //Adding element to Array List array.Add(new Person(”Ravi”, 28)); Person[] p = new Person[2]; p[0] = new Person(”Kiran”, 29); p[1] = new Person(”Kumar”, 27); Ravikiran

6.10. EXPLORING THE SYSTEM.COLLECTIONS NAMESPACE

141

// Adding Range of elements to an array array.AddRange(p); //Inserting new Element into an array array.Insert(0, new Person(”Bandari”,30)); // Removing element from an array array.RemoveAt(3); foreach (object o in array) { Person person = o as Person; Console.WriteLine(person); } } The Queue Class The Queue class implements a first-in first-out (FIFO) mechanism. An element is inserted into the queue at the back (the enqueue operation) and is removed from the queue at the front (the dequeue operation). The Queue class contains three methods 1. Dequeue() : Removes and returns the object at the beginning of the Queue 2. Enqueue() : Adds an object to the end of the Queue 3. Peek() : Returns the object at the beginning of the Queue without removing it Example static void Main() { Queue q = new Queue(); q.Enqueue(new Person(”Bandari”, 28)); q.Enqueue(new Person(”Ravi”, 27)); q.Enqueue(new Person(”Kiran”, 29)); while (q.Count >0) { Person p = q.Dequeue() as Person; Console.WriteLine(p); } Console.WriteLine(”Total Elements in Queue {0 }”,q.Count); // Prints ZERO } The Stack Class The Stack class implements a last-in first-out (LIFO) mechanism. An element joins the stack at the top (the push operation) and leaves the stack at the top (the pop operation). Ravikiran

142

CHAPTER 6. INTERFACES AND COLLECTIONS

static void Main() { Stack s = new Stack(); s.Push(new Person(”Bandari”, 28)); s.Push(new Person(”Ravi”, 27)); s.Push(new Person(”Kiran”, 29)); while (q.Count >0) { Person p = q.Pop() as Person; Console.WriteLine(p); } Console.WriteLine(”Total Elements in Stack {0 }”,s.Count); // Prints ZERO } The Hashtable Class The array and ArrayList types provide a way to map an integer index to an element. We provide an integer index inside square brackets (for example, [4]), and you get back the element at index 4 (which is actually the fifth element). However, sometimes we might want to provide a mapping where the type you map from is not an int but rather some other type, such as string, double, or Time. In other languages, this is often called an associative array. The Hashtable class provides this functionality by internally maintaining two object arrays, one for the keys you’re mapping from and one for the values you’re mapping to. When you insert a key/value pair into a Hashtable, it automatically tracks which key belongs to which value, and enables you to retrieve the value that is associated with a specified key. There are some important consequences of the design of the Hashtable class: 1. A Hashtable cannot contain duplicate keys. If we call the Add method to add a key that is already present in the keys array, we will get an exception. We can test whether a Hashtable already contains a particular key by using the ContainsKey method. 2. When we use a foreach statement to iterate through a Hashtable, you get back a DictionaryEntry. The DictionaryEntry class provides access to the key and value elements in both arrays through the Key property and the Value properties. Example static void Main() { Hashtable ht = new Hashtable(); ht.Add(”Ravi”, new Person(”Ravi”, 28)); ht.Add(”Kiran”, new Person(”Kiran”, 29)); foreach (DictionaryEntry element in ht) Ravikiran

6.10. EXPLORING THE SYSTEM.COLLECTIONS NAMESPACE

143

{ Console.WriteLine(”Key is {0 }”, element.Key); Console.WriteLine(”Value is {0 }”,element.Value); } }

Ravikiran

Sign up to vote on this title
UsefulNot useful

Master Your Semester with Scribd & The New York Times

Special offer for students: Only $4.99/month.

Master Your Semester with a Special Offer from Scribd & The New York Times

Cancel anytime.