Programming in CSharp

by Willi-Hans Steeb International School for Scientific Computing and E.J. Dembskey Version: 2008-08-28 email addresses of the authors: steeb_wh@yahoo.com steebwilli@gmail.com whsteeb@uj.ac.za evan.dembskey@gmail.com demskeye@tut.ac.za

Contents
1 Introduction 2 CSharp Basics 2.1 Introduction . . . . . . . . . . . . 2.2 Basic Data Types . . . . . . . . . 2.3 ASCII Table . . . . . . . . . . . . 2.4 Arithmetic Operations . . . . . . 2.5 Control Statements . . . . . . . . 2.6 Logical Operations . . . . . . . . 2.7 Pointers . . . . . . . . . . . . . . 2.8 Recursion . . . . . . . . . . . . . 2.9 Jump Statements . . . . . . . . . 2.10 Pass by Value, Pass by Reference 2.11 Arrays . . . . . . . . . . . . . . . 2.12 Bitwise Operations . . . . . . . . 2.13 Shift Operation . . . . . . . . . . 2.14 Commmand-Line Arguments . . . 2.15 Boxing and UnBoxing Types . . . 2.16 Delegates . . . . . . . . . . . . . 2.17 Types . . . . . . . . . . . . . . . 2.18 Reflection . . . . . . . . . . . . . 2.19 Generics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 6 6 8 10 11 13 17 18 19 20 21 24 27 28 29 29 30 31 32 33

3 String and StringBuilder 36 3.1 String Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36 3.2 Convert Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38 3.3 StringBuilder Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39 4 Built-in Classes 4.1 DateTime Class . . . . 4.2 Array Class . . . . . . 4.3 ArrayList Class . . . . 4.4 ListDictionary Class . 4.5 Class IEnumerator . . 4.6 Mathematics Class and . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Random Class i . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41 41 42 43 44 45 45

4.7 4.8 4.9

Point Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49 Class BitArray . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50 Object Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55 55 60 62 66 67 68 69 74 74 74 76 79 81 83 86 86 89 91 93 94 100 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104 104 105 105 106 107 109 110 111 113 115 116 117 122 123 124

5 Object-Oriented Programming 5.1 Write your own class . . . . . 5.2 Override Methods . . . . . . . 5.3 Inheritance . . . . . . . . . . 5.4 Overloading Methods . . . . . 5.5 Operator Overloading . . . . . 5.6 Structures . . . . . . . . . . . 5.7 Delegates . . . . . . . . . . .

6 Streams and File Manipulations 6.1 Introduction . . . . . . . . . . . 6.2 Binary File Manipulations . . . 6.3 Text File Manipulation . . . . . 6.4 Byte by Byte Manipulation . . 6.5 Object Serialization . . . . . . . 6.6 XML Documents . . . . . . . . 7 Graphics 7.1 Drawing Methods . . . . . 7.2 Color Class . . . . . . . . 7.3 Button and EventHandler 7.4 Displaying Images . . . . . 7.5 Overriding OnPaint . . . . 8 Events . . . . . . . . . . . . . . .

9 Processes and Threads 9.1 Processes . . . . . . . . . . . . . . 9.2 Threads . . . . . . . . . . . . . . . 9.2.1 Introduction . . . . . . . . . 9.2.2 Background Thread . . . . . 9.2.3 Sleep Method . . . . . . . . 9.2.4 Join Methods . . . . . . . . 9.3 Monitor . . . . . . . . . . . . . . . 9.4 Synchronization . . . . . . . . . . . 9.5 Deadlock . . . . . . . . . . . . . . . 9.6 Interlocked Class . . . . . . . . . . 9.7 Thread Pooling . . . . . . . . . . . 9.8 Threading in Windows Forms . . . 9.9 Asynchronous Programming Model 9.10 Timers . . . . . . . . . . . . . . . . 9.11 Interrupt and Abort . . . . . . . . ii

. . . .1 Introduction . . . . 135 11 Remoting 137 11. . . . . . . . . . .1 Introduction . . . . Bibliography Index 152 . .2 Examples . .3 Page Load . . . . . . . . 13. 127 . . . . . . . . .1 Introduction . . . .NET 13. 13. . . . . . . . . . . . . . . . . . 127 . . . . . . . . . . . . . . . . . . . . .2 State Management . . . . . . . . . . . 10. . . . . . . . . . . . . . . . . . 147 13 ASP. . . . . . . . . 153 155 155 iii . . . . . . . . . . . . . . 137 12 Accessing Databases 146 12.10 Sockets Programming 10. 152 . . . . . . . . . . .2 Transmission Control Protocol . . . . . . . . 152 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128 . . . . . . . . . . . . . . . . . . 146 12. . . .3 User Datagram Protocol . . . . . . . . . . . . . . . . . . . . . .1 Introduction . . . . . . . . . . . 10. . . . . . . . . . .

za iv . this book can be extended.uj.ac. The email addresses of the author are: whsteeb@uj. Without doubt.ac.Preface The book gives a collection of C# programs. we would be pleased to have them. If you have comments or suggestions.za steeb_wh@yahoo.com The web sites of the author is: http://issc.

double.accessible to containing class protected . By default classes are private. but at great performance cost. for example decimal. CSharp has a great set of tools for the object oriented programmer. The accessibility options are: public . In CSharp. CSharp unifies this with no performance cost. 1 . Collections work for all types. CSharp is the first component oriented language in the C/C++ family.NET framework. In Smalltalk and Lisp primitive types are objects. private is the default accessibility. events Design-time and run-time attributes integrated documentation using XML CSharp can be embedded in web pages (ASP.NET framework is object oriented.NET). CSharp also adds new primitive data types. The . CSharp is standardised as ECMA-334 by ECMA International and as ISO/IEC 23270 by ISO/IEC. In C++ and Java primitive date types (int. Component concepts are first class: Properties.Chapter 1 Introduction CSharp is designed for the . methods.accessible to containing or derived classes internal .means protected or internal Classes can be marked as public or internal.accessible to all private . etc) are magic and do not interoperate with objects.accessible to code in same assembly protected internal .

A single type can register interest in any number of events. In a derived class. Type constructors are used to initialize static fields for a type. We use the virtual keyword to make a method virtual. an override method is marked with the override keyword. Functions. INTRODUCTION Fields: The state of an object or type Methods: Constructors. Keywords are reserved identifiers that hold a special meaning to the CSharp compiler. for example if char c = ’a’. C# provides a mechanism for programmers to document their code using a special comment syntax that contains XML text. We can use the same name as a keyword identifier as long as we prefix the name with an @ symbol. Identifiers are case-sensitive. All types in the system are derived from class object. we can convert to an integer int i = (int) c. CSharp also provides type conversion.2 Type members in CSharp are: CHAPTER 1. This generator could be the C# compiler itself. . An identifier has to: begin with a letter. Constructors are used to initialize fields. It cannot be the same as built-in keywords. The following is a list of keywords. methods etc. We use the static keyword to indicate a type constructor.per object data and methods (default) Static .per type data and methods (use the static keyword). More than one type can register interest in a single event. The XML generation tool is called the documentation generator. Comments using such syntax are called documentation comments. Interfaces can contain methods but no fields with properties and events included. via the ASCII table. The names given to variables. CSharp supports interfaces using the interface keyword. This is useful for dealing with objects in an event driven operating system. We must implement all methods. Our types can implement interfaces. CSharp has built in support for events. We can indicate which base constructor to call by using the base keyword. or begin with an underscore. by the programmer are referred to as identifiers. We can implement simpler constructors in terms of more complex ones with the this keyword. The class object contains the functions string ToString() and bool Equals() which should be overriden when we write our own class. Properties (smart fields) Members come in two basic forms Instance .

Unlike with C and C++. these directives cannot be used to create macros. but are not reserved words. #if #elif #else #endif . from get group into join let orderby partial (type) partial (method) select set value var where (generic type constraint) where (query clause) yield Do avoid using class names duplicated in heavily used namespaces. directives are processed as if there was one. Some have meanings in two or more contexts. While the compiler lacks a separate preprocessor. These provide a specific meaning in the code. They aid in conditional compilation. for example. For example. do not use the following for a class name: System Collections Forms UI There are a number of preprocessor directives available. partial and where.3 abstract as base bool break byte case catch char checked class const continue decimal default delegate do double else enum event explicit extern false finally fixed float for foreach goto if implicit in int interface internal is lock long namespace new null object operator out override params private protected public readonly ref return sbyte sealed short sizeof stackalloc static string struct switch this throw true try typeof uint ulong unchecked unsafe ushort using virtual volatile void while The following is a list of contextual keywords.

A benefit of the CLR is that it provides these execution services to all . INTRODUCTION Languages: C#.1. 2005 or 2008 is installed. Vista or later is installed.exe is executed it does not interact .NET Framework. Cobol.0 and 3.NET applications without any additional effort on the part of the programmer.4 CHAPTER 1.1 for an overview of the stack.exe file does not contain directly executable instructions. Version 3. See Table 1. When the . VB.NET program is compiled.1: . or Common Language Runtime (CLR) provides a virtual machine for the execution of . the most important of which are the runtime and Class Library.5 adds several capabilities to the stack: the Windows Presentation Foundation (WPF). The current version of the .Net Framework is version 3. Jscript. The . thread management. Windows Workflow Foundation (WF). this . The runtime. garbage collection and default error handling.NET Framework is installed automatically when Windows Server 2003. When a . In addition. component lifetime management. Pascal Common Language Specification (CLS) Common Type System (CTS) ASP.0. The .5. SilverLight is a web-based subset of WPF. The . Windows CardSpace and Language Integrated Query (LINQ). 2.NET code. It is also installed when Visual Studio 2003.NET Framework consists of several components. VJ#. the compiler generates an . However. Instead it contains Common Intermediate Language (CIL).NET. but many machines still run 1.NET Framework is also available as a separate download from Microsoft.exe file. Windows XP SP2.NET Framework Stack #define #warning #line #endregion #pragma warning #undef #error #region #pragma #pragma checksum C# cannot be run without installing the . CLR provides services that include memory management. Windows Communication Foundation (WCF).NET Windows Forms XML Web Services Web Forms Data and XML Classes Base Framework Classes Common Language Runtime (CLR) Operating System Table 1.

This theoretically overcomes the performance overhead associated with using virtual machines. It contains all the types that represent the base data types such as text. with CIL being analogous to bytecode and CLR with the Java Virtual Machine(JVM).NET languages. cryptography. including user interface.Forms namespace allows the programmer to take advantage of the Windows forms engine to create graphical user interface objects easily.NET compatible. This is known as Just In Time compilation. .NET). This is similar to Java. web application development (ASP. The Common Language Specification (CLS) is a specification for creating or porting programming languages to that they are .NET).NET application is first executed. data access and database connectivity (ADO. The Class Library covers a wide range. When a . This is a component of the CLR and provides a common set of data types that are consistent between all . the CLR performs a compile of the CIL and creates a directly executable file from it. The Class Library is language-independent. The Systems.Windows. the System namespace is at the top of the namespace hierarchy. XML and network communications. The CLS uses uses a Common Type System (CTS). The Class Library is a collection of extensible class libraries organised hierarchically into namespaces. numeric algorithms. For example. numbers and dates.5 with the operating system directly but with the CLR.

Note that C# is case-sensitive.exe. // \n newline Console.WriteLine("Hello Egoli\n"). In the first example this is Hello1. The static modifier explains that this method works in this specific class only. To avoid fully qualifying classes throughout the program. class Hello1 { public static void Main() { Console. This is necessary.cs This generates an execute file named filename. Console.Chapter 2 CSharp Basics 2.1 Introduction Compile and link the programs with csc filename. In C# everything must be inside a class. we can use the using directive.WriteLine("Good Night Egoli"). 6 . Main is often called the entry point (starting address) of the program. // cshello. The method name. because when a program begins. where \n provides a newline.Write("midnight"). Thus also the Main method must be contained inside a class. rather than an instance of the class. Main. is reserved for the starting point of a program. In front of the word Main is a static modifier.cs using System. We write to the screen. A comment is indicated by //. This is also known as an executable assembly. no object instances exists.

With the using System. The System.2.WriteLine("Hello {0}". declaration. Namespaces contain groups of code that can be called upon by C# programs.Write(. indicates that we are referencing the System namespace. for example.) statement writes to the Console and stops on the same line. } catch(Exception e) { Console. but the Console. The expression string[] args defines an array of strings.WriteLine(. } Console. using System.cs using System. class Hello2 { public static void Main(string[] args) { try { Console.WriteLine("Good Night"). we are telling our program that it can reference the code in the System namespace without pre-pending the word System to every reference.1.Console class contains a method WriteLine() and a method Write() that can be used to display a string to the console. The difference is that the Console. . Strings are embedded in double quotes.. To access command line parameters we change the signature of the Main(void) to Main(string[] args).WriteLine(e). } // end Main } After compiling the program we run it with. // hello2.) goes to the next line after writing to the Console. for example "name". INTRODUCTION } // end Main } 7 The namespace declaration.args[0]). We write to the screen using exception handling with try and catch block.

short.8 Hello2 James CHAPTER 2. decimal .2 Basic Data Types Basic (primitive) data types are bool.WriteLine("Good Night"). Console.name)... Console.WriteLine("Enter your name: ").Length > 0) { Console. ulong float.WriteLine("Good Night").Read(). CSHARP BASICS To read from the keyboard we use the method ReadLine().WriteLine("Hello {0}". sbyte.WriteLine("Hello {0}". // Pauses the program until a key is pressed } // end Main } 2. int. We are also using an if-else construct. ushort. This problem can be solved using the Read() method to pause the window. Console. char. } Console. byte. The program above can be modified like so: .cs using System. The command Length returns the number of elements in the array. } else { Console. } // end Main } In the case of compiling using Visual Studio or some other IDE the problem of the program’s console window disappearing too quickly to view its output might occur. string name = Console.ReadLine().args[0]). uint. double. long. // hello3. class Hello3 { public static void Main(string[] args) { if(args.

BASIC DATA TYPES 9 The range of byte is 0.Char System.Double System.String System. The floating point number float is 4 bytes and the floating point number double is 8 bytes. CSharp is a strongly typed language and therefore variables must be declared with an available type and must be initialized with a value (or reference) of the same type.NET types described in the above table. // datatypes. char data type (2 bytes) in C# contains Unicode characters similar to Java..2. // character ’a’ ASCII value 98 Console. char f = ’\0’.UInt16 System. Apart from the above basic types the user may define his own types using enum.Object Description true/false unsigned byte value signed byte value a single character 16 bit signed integer 16 bit unsigned integer 32 bit signed integer 32 bit unsigned integer 64 bit signed integer 64 bit unsigned integer 32 bit floating point 64 bit floating point a high precision double string of characters a generic type At compile time the C# compiler converts the C# types into their corresponding .Byte System.WriteLine(e).WriteLine(!b).UInt64 System.SByte System. .2.WriteLine(f).Single System. // boolean data type Console.UInt32 System. // ! is the logical NOT // character 2 bytes Unicode char e = ’a’. // null character ASCII value 0 Console.Decimal System. struct and class.. where ushort is unsigned.Int64 System.Boolean System.NET Type System. Built-in types are also string and object. int and uint are 4 bytes.255 and for sbyte is -128. C# bool byte sbyte char short ushort int uint long ulong float double decimal string object .Int16 System.cs using System. class Datatypes { public static void Main() { bool b = true.Int32 System. short and ushort are 2 bytes (16 bits).127.

WriteLine(m).WriteLine(k).WriteLine(i)..255 // signed byte -128. int i = -100000. ushort h = 20000. Console. in other communication equipment. CSHARP BASICS // default integer type byte c = 255.145... short g = -10000..14159.2147483647 // unsigned int 0.3 ASCII Table ASCII (American Standard Code for Information Interchange) is a character set and a character encoding based on the Roman alphabet as used in modern English. ASCII reserves the first 32 codes (numbers 0-31 decimal) for control characters.WriteLine(h). long k = -234567899.. and in control devices that work with text.65535 (2 bytes) // signed int -2147483648. Console..WriteLine(c). ulong l = 3456789123.127 // short -32768.WriteLine(n).WriteLine(p).WriteLine(g). } } Note that (data type) is the type conversion operator.. Console. // double 64 bits Console. 2. c++.. is int // unsigned byte 0. Console... ASCII is. The capital ’A’ is 65 (decimal) .. a seven-bit code. // float 32 bits Console. Console.4294967295 // signed long 64 bits -2^63.. ASCII codes represent text in computers. Console.WriteLine(j)... strictly. d--. // decimal 128 bits decimal p = (decimal) 2.2^64-1 // default floating point number is double // (float) type conversion from double to float float m = (float) 3.2^63-1 // unsigned long 64 bits 0.32767 (2 bytes) // unsigned short 0.89124357865678. uint j = 200000.10 CHAPTER 2. double n = 3. sbyte d = -125. meaning that it uses the bit patterns representable with seven binary digits (a range of 0 to 127) to represent character information... ASCII specifies a correspondence between digit bit patterns and the symbol of a written language. // type conversion Console. Console.WriteLine(l).

// 12 char c3 = ’\n’. // form feed int i2 = (int) c2. /. The null character is ’\0’.WriteLine("i4 = " + i4). *.4. // Escape. // 9 char c6 = ’ ’. // 32 } // end Main } 2. // newline int i3 = (int) c3. // 8 char c2 = ’\f’. // ASCII value Console. // backspace int i1 = (int) c1. -. 11 We are doing type conversion from char -> int using the ASCII table. // ASCII value Console.2. +.WriteLine("i2 = " + i2). // ASCII value Console. // 10 char c4 = ’\r’. --.WriteLine("i3 = " + i3). // ASCII value Console. // ASCII value Console. // ASCII value Console.WriteLine("i5 = " + i5). // carriage return int i4 = (int) c4. // 13 char c5 = ’\t’. % .WriteLine("i1 = " + i1). The type conversion operator is (data-type). // horizontal tab int i5 = (int) c5. Furthermore ’0’ is 48 and ’9’ is 57.cs using System. // blank int i6 = (int) c6.WriteLine("i6 = " + i6). ARITHMETIC OPERATIONS and the small ’a’ is 97. Space is 32. class Escape { public static void Main() { char c1 = ’\b’.4 Arithmetic Operations The arithmetic operations are ++.

int r1 = 27.WriteLine(d). float f1 = (float) 3. int r4 = r1%r2. // integer division Console. Console. int r2 = 5. Note that we have integer division (for example 17/4 = 4) and floating point division depending on the data types. // signed int int j = 15002. // remainder Console. Console. // signed long long n = 345.145. double d2 = 4. // arithmetic. int r3 = r1/r2.WriteLine("r3 = " + r3).81. sbyte d = -125. long m = -234567899.14159.5. . // signed byte d--.12 CHAPTER 2. c++. int i = -100000. CSHARP BASICS where ++ is the increment by 1 and -. float f3 = f1*f2. // type conversion float f2 = (float) 2.WriteLine(c).WriteLine(p). The operation % provides the remainder in integer division. double d1 = 3. Console. Console. int k = i + j. Console.WriteLine(f3).WriteLine("r4 = " + r4). class Arithmetic { public static void Main() { byte c = 255.cs using System. long p = m*n.is the decrement by −1.WriteLine(k).

Convert.89124357865678. Console. string line = Console.WriteLine(d3). else Console. CONTROL STATEMENTS double d3 = d1/d2.ToInt32(line).5 Control Statements Control statements control the program flow. // type conversion decimal p2 = (decimal) 3. decimal p1 = (decimal) 2. For example. Console.WriteLine("The number is larger than 5").2. // myIf. class forloop { public static void Main() { .ReadLine(). // forloop..5.14159.cs using System. class myIf { public static void Main() { int i.WriteLine("The number is smaller than 5 or equal to 5"). Console. } } 13 2. else and switch use certain criteria to select a course of certain action within the program. selection statements such as if . // convert string of digits to int if(i > 5) // if true do the next command else skip it Console. i = System.WriteLine(p3). } // end Main } The for loop applied to a one-dimensional array..WriteLine("Enter integer: "). // type conversion decimal p3 = p1 + p2.cs using System.

i++) // Length provides length of array { sum += numbers[i].i++) { intsum += x[i]. for(i=0.sum).i<numbers. 2. // sum = sum + numbers[i]. x[2] = 7. Note that ! is the logical NOT and ToInt32(string) converts a string of digits to an integer. // shortcut for intsum = intsum + x[i]. } // end Main } The foreach loop can be applied to an array of strings. int intsum = 0.i<x.ToInt32(line). .In. int[] x = new int[3]. // initialize sum to 0 String line. for(line=Console. } Console.ReadLine()) { sum += System.line!="". int i = 0. } Console. x[1] = 3.2.Convert. CSHARP BASICS double[] numbers = { 1. 4. double sum = 0.cs using System.ToString() + "\n").ReadLine().WriteLine(intsum).Length.line=Console. class ForLoop { public static void Main() { int sum = 0. // declare array and allocate memory x[0] = 4.WriteLine(sum. We count how often the string "otto" is in the array of strings. 3. } // end for loop Console.In. } // end Main } Another example for the for loop applied to numbers read from the keyboard. // forloop1.0.Length.3. for(i=0.WriteLine("sum = {0}".4 }.1.14 CHAPTER 2.

Length) { sum += numbers[i].2. int i = 0.count). } } // end foreach Console. while(i < numbers. 3. string n = "otto". } Console. class foreachloop { public static void Main() { string[] namelist = { "willi". int sum = 0. } // end Main } 15 . 2. 4 }. } // end Main } The while loop // whileloop.WriteLine("count = {0}". i++. foreach(string name in namelist) // keyword in { if(name == n) // compare strings for equality case sensitive { count++. int count = 0.cs using System."carl". CONTROL STATEMENTS // foreachloop."otto" }."otto".WriteLine("sum = {0}".5.sum)."john". class whileloop { public static void Main() { int[] numbers = { 1.cs using System.

switch(c) { case ’a’: Console. double sum = 0. } // end Main } If one has a large decision tree and all the decisions depend on the value of the same variable we use a switch statement instead of a series of if . for(int i=0. class Myswitch { public static void Main() { string st = "bella".16 CHAPTER 2. 4.WriteLine("sum = {0}". do { sum += numbers[i]..3.cs using System. else constructions. class whileloop { public static void Main() { double[] numbers = { 1. // switch.cs using System. Note that if the break is omitted. CSHARP BASICS The do-while loop applied to an array of floating point numbers. .Length.0. 3. The break statement can also be used to break out of an iteration loop. int i = 0. 2.i++) { char c = st[i]. depending on the value of the switch expression.i<st. execution will continue over the remaining statements in the switch block. // dowhileloop.. i++. } while(i < numbers.1.sum). The switch statement transfers control to one of several case-labeled statements.WriteLine("character is a ’a’ ").5.Length). Console.5 }.

4.4. 17 for(int j=0.2.j).ReadLine().WriteLine("character is a ’b’ "). C++ and Java are && logical AND || logical OR ! logical NOT // logical.1.WriteLine(" Enter an integer: ").j). break. break. } // end switch } // end for loop } // end Main } 2.1.6.6}. default: Console. Console.WriteLine("character is not an ’a’ or a ’b’ "). C.j<numbers.Convert. break.WriteLine("number at position {0} is 4".j++) { switch(numbers[j]) { case 4: Console. } } // end for loop int[] numbers = { 3. j = System. case ’b’: Console. .-3. break.WriteLine("number at position {0} is 6".Length. break.ToInt32(line).j).6. case 6: Console. LOGICAL OPERATIONS break. default: Console. class MyLogica { public static void Main() { int j.6 Logical Operations The logical operators in CSharp.cs using System.WriteLine("number at position {0} is not 4 or 6". string line = Console.

Console.WriteLine("The integer is nonzero"). int k.ReadLine(). The dereference operator is *. k = System.WriteLine("The integer is zero"). Console. Console. class Pointers { .WriteLine("The integer is either odd or larger than 10 or both"). Obtaining the value that a pointer referes to is called dereferencing.Convert. if(n == 0) Console. } } 2.WriteLine("Enter an integer: "). if((k > 0) || (k < 0)) Console.Convert. // Pointers1.cs using System. else Console.WriteLine(). Console. line = Console.ToInt32(line).WriteLine("The integer is nonzero"). int n. line = Console.WriteLine("The integer is zero").WriteLine("Enter an integer: "). Pointers in CSharp must be declared unsafe.18 CHAPTER 2.ToInt32(line).WriteLine("The integer is even and smaller than 10"). n = System. Thus the pointer has an address and contains (as value) an address.7 Pointers A pointer is a data type whose value refers directly to (”points to”) another value stored elsewhere in the computer memory using its address.WriteLine(). else Console. else Console. CSHARP BASICS if((j%2 == 0) && (j < 10)) Console.ReadLine().

8. We use recursion to find the Fibonacci numbers.WriteLine("r = " + r). RECURSION public static unsafe void Main() { int i = 15. A recursion needs a stopping condition.WriteLine("b2 = " + b2). } // end Main } . int* q = &j.result). // recursion. ulong result = fib(n). // false // dereferencing pointers int r = *q. Console. // 15 } } We are using pointer to pass by reference (see section 2.8 Recursion Recursion plays a central role in computer science. } // end fib public static void Main() { ulong n = 10.cs using System. if(n == 1) return 1. int* p = &i. // true bool b2 = (p == q).WriteLine("Result = {0}". class recur { public static ulong fib(ulong n) { if(n == 0) return 0. return fib(n-1) + fib(n-2). Console. bool b1 = (i == j). A recursive function is one whose definition includes a call to itself. Console.2. Console.WriteLine("b1 = " + b1). // declare pointer and assignment to address of i int j = 15.10). 19 2.

Next(100).a. } L4: int e = 0. string s = Console. Console. L4 if a condition is met.ReadLine(). goto L1. // mygoto.20 CHAPTER 2. L2: Console.WriteLine("congratulations you are correct"). int b = r.cs using System. see you next time around"). It is part of the class Environment. string t = Console.Next(100).WriteLine("sorry you are not correct: try again").ToInt32(s).WriteLine("Want to add again: Press y for yes and n for no: "). if(t == "n") { Console. We use the goto to jump to the labels L1. if(result == (a+b)) goto L2. } } The method Exit() is used for program termination. class Mygoto { public static void Main() { Random r = new Random(51). // password. goto L4.b).9 Jump Statements C# also has an goto for jumping to labels. L2. Console. L3: int a = r. CSHARP BASICS 2.ReadLine().cs .WriteLine("bye. L3. if(t == "y") goto L3.WriteLine("{0} + {1} =". result = Convert. int result. L1: Console.

s).i<91.Exit(0).i++) { for(j=65.WriteLine("Password = {0}". and the associated parameter is the same as a local variable for the function.k<91. change in the parameter also alter the original argument. char c2 = (char) j. not the originals.10. PASS BY VALUE. char c3 = (char) k. Environment. Thus functions that receive pointers to variables gain access to the original variables associated with the pointers. This means.2. string s = new string(data). for(i=65. Pass by Reference Arguments to functions can be passed either by value or by reference. PASS BY REFERENCE using System. int i. The alternative. is indicated by the presence of the keyword ref in the argument list.k++) { char c1 = (char) i. } } } } } } 2. a copy of the argument is produced. // converting array of char to string bool found = password.c2. In C# we can also use pointers and the dereference operator to pass by reference. When an argument is passed by value.10 Pass by Value. .j<91. changes to the parameter variable will have no effect on the original argument value.j. the parameter variable is an alias for the argument value. Functions that receive variables as parameters get local copies of those variables.j++) { for(k=65. 21 class password { public static void Main() { string password = "XYA". char[] data = { c1. pass by reference.c3 }. Thus.Equals(s). When arguments are passed by reference. if(found == true) { Console.k.

} public static unsafe void Main(string[] args) { int a = 10. Console.WriteLine("i inside function add = " + i). *q = t. // Pitfall.cs using System.&b.int* q.add(int). int b = 12. rot(&a.cs using System. i = n. Console. add(i). public class Pitfall { public static void add(int i) { int n = i + i. *r = *p. In the next program we use pointers to pass by reference. CSHARP BASICS In the next program we pass by value. public class Rotate { public static unsafe void rot(int* p. // 10 } } Note that without static in method add(int): error message: An object reference is required for the nonstatic method Pitfall. // 20 } // end add public static void Main() { int i = 10. We rotate integer numbers. *p = *q.int* r) { int t = *r. . // pointers2.&c).WriteLine("i in Main = " + i).22 CHAPTER 2. int c = 17.

p = q. . string s2 = "111". // passing.cs using System.WriteLine("a = {0} and b = {1} and c = {2}". } // end Main } In the following program we pass the first argument by reference and the second by value.2. sb = "222".b. rot(ref a. PASS BY REFERENCE Console. } public static void Main() { int a = 10. q = t. public class Rotate { public static void rot(ref int p.c).cs using System.ref c). // references.a.string sb) { sa = "yyy". int b = 12. PASS BY VALUE.WriteLine("a = {0} and b = {1} and c = {2}".b.ref int r) { int t = r. } // end main } 23 In the following program we use the keyword ref to pass by reference. We rotate three integers.ref b.c). public class Passing { static void change(ref string sa. r = p.a. } public static void Main() { string s1 = "xxx".ref int q.10. int c = 17. Console.

return quot. A variable using this keyword must not be initialized before the method call.out int r) { int quot = dividend/divisor.cs using System. r = dividend . // => s1 = yyy s2 = 111 } } The out keyword explicitely speciefies that a variable should be passed by reference to a method. int t.Write("s1 = {0} and s2 = {1}". C# supports one-dimensional arrays.int divisor. } // end Main } 2.out t).24 CHAPTER 2. } // end Divide2 public static void Main() { int r.out int r) { quot = dividend/divisor. and set in that method. These are accessed through computed indices.quot*divisor. r = dividend . multidimensional .3. } // end Divide1 public static void Divide2(int dividend. Console. // Divide.WriteLine("Quotient = {0} and Remainder = {1}".s.int divisor.q.r).quot*divisor. Divide2(145. CSHARP BASICS change(ref s1.out s. int s.out int quot.s2). class Divider { public static int Divide1(int dividend.11 Arrays An array is a data structure that contains a number of variables.s2).14. int q = Divide1(123.out r).WriteLine("Quotient = {0} and Remainder = {1}".s1. Console.t). Console.

23456789 }. int numb = Array.11. Console.cs using System.WriteLine(). System. 1. double[] d = new double[3]. not the identifiers.9). As C. Thus int[] numbers = new int[20].Write("prod = " + prod). int prod = numbers[2]*numbers[0]. Array.Array is the abstract base type of all array types. int dpos = Array. The size of the array is not part of its type as it is in the C language. Console.Write("\n"). Console. the square bracket [] must come after the type. 5}. 1. d[2] = 8. string[] slist = { "otto".Sort(slist).4.BinarySearch(numbers. class myArray { public static void Main() { int[] numbers = { 4. "marius". ARRAYS 25 arrays (rectangular arrays) and arrays of arrays (jagged arrays). int pos1 = Array. 890. "uli". for example int[] table. Console.Write("\n")."carl").Write("\n").8. 2. // sorting the array .Write("dpos = " + dpos).2. 5}. Console. C++ and Java C# arrays are zero indexed.BinarySearch(slist. 3. Console. 2. 3. We can initialise arrays very simply: int[] numbers = {0.Write("pos1 = {0}". This means the array indexes start as zero. When declaring arrays. "carl". The class Array contains methods for sorting and searching. Console.9. 12345.pos1). d[0] = 1. // myArray.1.BinarySearch(d. This is identical to the complete initialisation statement: int[] numbers = new int[] {0. d[1] = 3. "jacob" }. Console. In C# arrays are actually objects.Write("numb = " + numb).4).

WriteLine(). Thus: int[.] numbers = {{0. 1] = 14. 6}. for(int j=0. numbers[1. The length of each dimension of the array is determined by the number of elements at the corresponding nesting level in the array initializer. numbers[4.26 CHAPTER 2. } } } To create multidimensional arrays the array initializer must have as many levels of nesting as there are dimensions in the array. 12. 10}. Console. numbers[3. 1] = 2.slist[j]). The element arrays do not all have to be the same. {8. 18}}. We can also create jagged arrays. 1] = 10. {4. 16.BinarySearch(slist. // twodim. 1] = 18. which are arrays of arrays.WriteLine("{0} {1}". Or: int[. The innermost nesting level corresponds to the rightmost dimension.j<slist. 1] = 6. public class TwoDim { public static void Main() { int[][] matrix = new int[2][]. Thus the example above creates a two-dimensional array with a length of five for the leftmost dimension and a length of two for the rightmost dimension. {12. The outermost nesting level corresponds to the leftmost dimension.Write("pos2 = {0}". numbers[2.j.Length. // rows . CSHARP BASICS int pos2 = Array. 2}."carl").j++) { Console. numbers[1.cs using System. numbers[3.pos2). numbers[2. 8. {16. 2]. numbers[0. 17}. and initialises the array with: numbers[0.] numbers = new int[5. Console. 0] 0] 0] 0] 0] = = = = = 0. numbers[4. 4.

myarray[1.2] = 3. Console. double r = myarray[0.WriteLine("matrix[" + i + "][" + i + "] = " + matrix[i][i]).1] = 1. myarray[0. double[. 17 = 1 · 101 + 7 · 100 . class MylBitwise { public static void Main() { .cs using System.1]*myarray[1.7.12 Bitwise Operations Consider the integer number 17 (base 10. C. int i = 1. BITWISE OPERATIONS 27 matrix[0] = new int[2].1] = 4. myarray = new double[2.] myarray.3. myarray[1.7. myarray[0. } // end Main } 2. matrix[1][1] = 3.1.12.2.e.3.0] = 2.WriteLine("r = " + r). matrix[1][0] = 7. i. myarray[0. // columns matrix[0][0] = 2.2] = 7.2].3]. Thus the binary representation of 17 would be 10001. C++ and Java are: & | ^ ~ AND OR (inclusive OR) XOR (exclusive OR) NOT // bitwise. myarray[1. matrix[0][0] = 4. It can be written in binary as 17 = 1 · 24 + 0 · 23 + 0 · 22 + 0 · 21 + 1 · 20 . Console.0] = 3. // columns matrix[1] = new int[2]. If 17 is considered as data type int (32 bits) we have the binary representation 00000000000000000000000000010001 The bitwise operation in CSharp.1.

.. 4.. int r7 = 11.WriteLine("Binary NOT of r9 gives {0}". by 2 8 by 4 4 . 4. // integer divison Console.r10).r11). .r5). Console. // => int m = 9.r9). int r6 = 7. // one’s complement int r14 = ++r13.r8).cs using System. // bitwise AND Console. int r8 = r6 | r7.WriteLine("Binary XOR of 7 and 11 gives {0}".WriteLine("Binary XOR of 125 with itself gives {0}". int r12 = 4. class Shift { public static void Main() { int i = 17. // bitwise OR Console. //bitwise XOR Console.WriteLine("j = " + j).WriteLine("k = " + k). int x = 125.. // integer divison Console.WriteLine("two’s complement of 4 {0}". int r9 = r6 ^ r7. int r13 = ~r12.r14). The shift operations are << and >>. int r11 = ~r9. . int r5 = r3 & r4. and fast integer division by 2.28 CHAPTER 2. Console.13 Shift Operation We can use shift operation for fast integer multiplication by 2. 8.WriteLine("Binary AND of 4 and 5 gives {0}". int r10 = x^x.WriteLine("Binary OR 7 and 11 gives {0}". } } 2.. Console. // MyShift. CSHARP BASICS int r3 = 4. // 17 in binary 10001 int j = i >> 1. int r4 = 5. // => int k = i >> 2. 8.

exe) compiles a C# program it marks the Main method as the entrypoint in the generated IL code.WriteLine("p = " + p). This array will always contain the command line arguments passed to the program by its user.WriteLine("i={0}". // multiplication by 2 Console. COMMMAND-LINE ARGUMENTS int n = m << 1. and unboxing refers to the opposite. // => 18 int p = m << 2. Boxing is carried out implicitly in C#. Console.i). We start counting from zero. Comsole.14 Commmand-Line Arguments C# enables us to access command-line arguments by supplying and using the following parameters in function Main Main(string[] args) Basically a C# program consists of a class with a static member method (class function) called Main. // multiplication by 4 Console. For example int i. // CommandLine. .").cs using System. whereas we have to use type casting to unbox to an appropiate data type.14.args[0]).15 Boxing and UnBoxing Types Boxing refers to converting a value type to an object type.WriteLine("Hello{0}".2. // => 36 } } 29 2.WriteLine("n = " + n). for example CommandLine World 2. When the C# compiler (csc. The Main method may accept an array of string as its arguments (though this is optional).WriteLine("Goodbye. class CommandLine { public static void Main(string[] args) { Console. } } We run the program. The following program shows an application.

} // end Main static void FirstMethod(string s1.int b). md("message A".11). md += new MyDelegate(SecondMethod). An example for unboxing is int i. int sum1 = x1 + y1.int a. If the object being unboxed is null or if the unboxing cannot succeed because the object is of a different type. j = (int) obj. Delegates are type safe function pointers. class Application { public static void Main() { MyDelegate md = new MyDelegate(FirstMethod). // to unbox we use type cast Typically unboxing is done in a try block.16 Delegates A delegate essentially creates a name for a the specific type/signature of a method.5). so in the above statement integer i is implicitly boxed to an object and passed to the WriteLine method. // delegates.int y2) { . // declare delegate with the signature of the // encapsulated method delegate void MyDelegate(string m.int y1) { Console. Console. One must first declare a delegate.4.int x1. 2. CSHARP BASICS The WriteLine() method requires an object.30 CHAPTER 2.WriteLine("sum1 = " + sum1).WriteLine("1st method: " + s1). an InvalidCastException is thrown. // boxing is implicit int j.cs using System.int x2.7. md("message B". object obj = i. } static void SecondMethod(string s2.

class myTypeof { public static void Main() { double b = 3.17 Types The typeof command is an operator. if(s is StringBuilder) Console. Console. if(s is string) Console.cs using System.Text. Type at = typeof(double).sbt). TYPES Console. // myTypeof. Console. Type st = typeof(string). } } The output is 1st method sum1 = 9 2st method sum2 = 9 1st method sum1 = 18 2st method sum2 = 18 message A message A message B message B 31 2.WriteLine("st = {0}". int sum2 = x2 + y2. StringBuilder sb = new StringBuilder("123456789"). Console. Console. string s = "xxx".WriteLine(at).14. .WriteLine("sum2 = " + sum2). To check whether an object is compatible to a specific type is to apply the is keyword.WriteLine("at = {0}".17.WriteLine("2st method: " + s2).WriteLine("sbt = {0}". Type sbt = typeof(StringBuilder). It resolves at compile time and operates over a type.2.st). using System.Write("s is of the StringBuilder").at).

From the declaration type: If declaration AType var is legal then System. class ShowTypes { public static void Main(string[] args) .Type class the reference to which can be obtained using one of the following methods.cs using System. if(b is int) Console. 1. 4. } } 2.Reflection.Type representing AType can be obtained using the typeof operator as: Type t = typeof(AType). This reference can be used to obtain the Type with a given name: using System. From the type name within any assembly: First load the assembly and obtain a reference to it. From the type name within current assembly: System.Reflection.Type offers a static method called GetType to obtain a Type from a fully qualified name of the type.Write("s is not of StringBuilder").WriteLine("b is int"). The program showtypes.LoadFrom("AssemblyName"). Assembly asm = Assembly. CSHARP BASICS else Console. 2. From an instance: Type of an instance obj can be obtained using GetType method defined in System. The type of an object is stored as an instance of System.32 CHAPTER 2. The name will be searched in the current assembly Type t = Type.GetType("FullyQualifiedTypeName"). 3.cs displays all the Types defined in an assembly whose name is passed in as first command line argument: // showtypes.18 Reflection Exposing and utilizing types at runtime is called reflection.GetType(). using System. Type t = asm.GetType("FullyQualifiedTypeName").Object as Type t = obj.

using System.cs using System. Generics introduce to the . . Type t = asm.LoadFrom(args[0]). } } We would run the program as.NET exe or dll to see the types declared in it. // showmembers.NET Framework class library contains several new generic collection classes in the System. foreach(Type t in types) Console. MemberInfo[] members = t. 33 The next program showmembers.19 Generics C# Generics are similar to C++ Templates.19. foreach(MemberInfo m in members) Console.WriteLine(t).0 of the C# language and the common language runtime (CLR).cs takes the assembly name and type name as its command line arguments and displays all the members defined in that type of assembly.Reflection. class ShowMembers { public static void Main(string[] args) { Assembly asm = Assembly. This makes it possible to design classes and methods that defer the specification of one or more types until the class or method is declared and instantiated.GetType(args[1]).NET Framework the concept of type parameters. for example showtypes datatypes.exe Pass complete path to any .Generic namespace. GENERICS { Assembly asm = Assembly.WriteLine(m).GetMembers(). The standard example provided by Microsoft is a generic stack. The . They were introduced in version 2.2.GetTypes(). } } 2.Collections.LoadFrom(args[0]). Type[] types = asm.

. int m_StackPointer = 0. int number = stack. } else { m_StackPointer = 0. if(m_StackPointer >= 0) { return m_Items[m_StackPointer]. } public T Pop() { m_StackPointer--.. public Stack():this(100) {} public Stack(int size) { m_Size = size.. m_StackPointer++. public void Push(T item) {. stack. CHAPTER 2..} } Stack<int> stack = new Stack<int>(). The generic stack code is public class Stack<T> { readonly int m_Size. m_Items = new T[m_Size].Pop(). stack. } public void Push(T item) { if(m_StackPointer >= m_Size) throw new StackOverflowException().} public T Pop() {.34 public class Stack<T> { T[] m_Items. m_Items[m_StackPointer] = item.Push(1). T[] m_Items.Push(2). CSHARP BASICS .

GENERICS throw new InvalidOperationException("Cannot " + "pop an empty stack").2. } } } 35 .19.

Even though it appears that the application is changing the value of the string instance. // => annes 36 . int length = s1. // => 4 string s2 = "willi".1 String Class The most importent built-in class is the string class.’t’).WriteLine(result). The string class and the StringBuilder class provide ways to perform string manipulations.WriteLine(s2).cs using System.Length.WriteLine(length).Chapter 3 String and StringBuilder 3. s2 = s2. // => otto Console. // witti string s3 = "Johannesburg". it is actually returning a new instance of the string class in memory. it cannot be changed. class mystring { public static void Main() { string s1 = "otto". string result = s3. Console.Substring(3.Replace(’l’.WriteLine(s1). Console. // mystring.5). which means that once the value of the string instance is set. The string class provides an immutable object string s = "Hello". Console.

WriteLine("s11 = " + s11). STRING CLASS 37 string s4 = "olli&ulli&ruedi". Console. // => False // copy a string string s15 = string. Console. ’p’.WriteLine(s7).WriteLine("s15 = " + s15). string s11 = s10. // => XENA string s10 = "WILLI HANS".Join(":". Console. Console. // stringarrays. } // end Main } Arrays of strings can be implemented as follows.WriteLine("s14 = " + s14). string s7 = new string(s6).ToLower(). // => willi hans // use + to concatenate strings string s12 = "Carl-". // use Equals() to compare strings // case sensitive bool b1 = s12. // => ulli string s5 = string. Console.Split(’&’).Copy(s14). Console. Console.textarray).WriteLine("b2 = " + b2). string s14 = s12 + s13. // => False // can also use overloaded == to compare strings // case sensitive bool b2 = (s12 == s13). string[] textarray = s4.1.cs . // => olli:ulli:ruedi char[] s6 = { ’o’. string s13 = "Otto".WriteLine(textarray[1]). string s9 = s8. // => opa string s8 = "xeNa".ToUpper().WriteLine(s5).3. Console. ’a’ }. Console.WriteLine("b1 = " + b1).Equals(s13).WriteLine(s9).

class stringarrays { public static void Main() { // one-dimensional array of strings string[] keywords = new string[] { "as".cs using System. "xena" }. "in" }."two"}. "if". // => xena // two-dimensional array of strings string[. public class MyConvert . Console. The methods are string ToString(T x) // any numerical type bool ToBoolean(string s) byte ToByte(string s) char ToChar(string s) short ToInt16(string s) int ToInt32(string s) long ToInt64(string s) float ToSingle(string s) double ToDouble(string s) decimal ToDecimal(string s) An example is // MyConvert.2 Convert Class Using the Convert class we can convert string to numbers (integers and floating point) and numbers (integers and floating point) to strings.WriteLine(keywords[3])."three"}}.0]).WriteLine(strArry[2. STRING AND STRINGBUILDER using System.0]).WriteLine(strArry[0. // => in // one-dimensional array of strings string[] names = { "willi". {"2". Console. "do". "ola". // => 1 Console. {"3".] strArry = {{"1"."one"}.WriteLine(names[2]). // => 3 } // end Main } 3.38 CHAPTER 3. Console.

int j = Convert. string s3 = "3.3. string s1 = Convert.Text. // for StringBuilder class mystringbuilder { public static void Main() { string s = "carl".WriteLine("c = " + c). It is called mutable because it can be modified once it has been created by using the methods Append(). string s2 = Convert.cs using System.ToInt32("12345").Text. . using System.WriteLine("b = " + b).14159".ToString(i). Console.Text namespace.Length+12). STRINGBUILDER CLASS { public static void Main() { int i = 34.3. // mystringbuilder. Console.WriteLine("j = " + j).3 StringBuilder Class The StringBuilder class represents a mutable string a characters.WriteLine("s1 = " + s1).ToDouble(s3). Console. double y = Convert. char c = Convert. Console. using System. Insert(). } } 39 3.WriteLine("y = " + y). Console. Remove() and Replace().14159. StringBuilder b1 = new StringBuilder(s. bool b = Convert. Console.WriteLine("s2 = " + s2). Thus we have to add the following line in our application. Using the StringBuilder class.ToString(x). The StringBuilder class is defined in the System.ToChar("x"). double x = 3.ToBoolean("true").

’:’).Append("10").C b2.WriteLine(b1).i++) Console. using System.40 CHAPTER 3."). Console. StringBuilder tm = mythuemorse(n-1).Remove(3. // thuemorse. i. class ThueMorse { public static void Main() { for(int i=0.Remove(4. // => A:B:C StringBuilder b3 = new StringBuilder("stringbuilder"). b2.C"). // => carl-uli b1. Console.50).WriteLine(b3).e. b3.cs using System.Length. } } .Append("carl").9).Replace(’. } public static StringBuilder mythuemorse(int n) { if(n == 0) return new StringBuilder("0". return tm2. // => stri } } Another application of the StringBuilder class is given by generating the ThueMorse sequence. else tm2. the method mythuemorse calls itself. STRING AND STRINGBUILDER b1.i++) if(tm[i] == ’0’) tm2.30).WriteLine(b1). b1. Console.Append("-uli").WriteLine(mythuemorse(i)).i<tm. We apply recursion.i<7. Console. // => caruli StringBuilder b2 = new StringBuilder("A.WriteLine(b2).WriteLine(b2).Text. StringBuilder tm2 = new StringBuilder("". // => A.Insert(2."B.B.2). Console.’.Append("01"). for(int i=0.

Month.Second). Today returns the current date.WriteLine("Time output: {0}:{1}:{2}".Chapter 4 Built-in Classes 4.dt. For formatting we could use d which would be the short date mm/dd/yyyy. 2005. // myDate.dt.Day).Minute.cs using System. } 41 .dt.WriteLine("Date output: {0}\\{1}\\{2}". Console. Console. DateTime today = DateTime. j++. Console.dt).ToString().WriteLine("Today is: {0}".Millisecond.Now.Hour.dt. // 7/29/2006 3:18:03 PM string s = dt. for example 9/24/2005 and D would be Saturday. for(uint j=0.j++) { j = j*2.WriteLine("s = " + s).Year. The DateTime class stores both a full date and the full time. September 24.j<10000000. The two static members are Now and Today.WriteLine("milli1 = " + milli1). j--.today). DateTime m1 = DateTime.dt. Console. Console. class myDate { public static void Main() { DateTime dt = DateTime. Console.Today. Now contains the date and time for the moment the call is made.WriteLine("Date Time output: {0}".Now. j = j/2. int milli1 = m1.dt.1 DateTime Class To get the dates and time we use the DateTime class.

//using System. . Console.int index.object value).WriteLine("d: {0:d}". 56. p1). Console. ICollection. IEnumerable.int length). An example is // MyArray.currTime).WriteLine("milli2 = " + milli2).877). void Reverse(Array array. 123.object value). int BinarySearch(Array array. int diff = milli2 .int length. Console. class MyArray { public static void Main() { int[] a1 = { 669.IList. void Reverse(Array array). // Formats DateTime currTime = DateTime.cs using System.WriteLine("p1: {0}". September 24. For example int BinarySearch(Array array. Console. public virtual object Clone().Array destination. 877.int index. void Copy(Array source. // 9/24/2005 Console.42 CHAPTER 4. // Saturday. void Clear(Array array. 777 }.WriteLine("D: {0:D}".object value). 2005 } } 4.Now.int length).Millisecond.WriteLine("diff = " + diff). int milli2 = m2.BinarySearch(a1. IList cotains methods for manipulations of arrays.milli1. int IndexOf(Array array. 45. 456.2 Array Class The Array class class Array : IClonable.currTime).Collections.int length). int p1 = Array. BUILT-IN CLASSES DateTime m2 = DateTime.Now.int index.

for(int i=0. // arraylist. but cannot restrict the number of elements it may contain. for(int i=0.3. Array. "ana" }. foreach(string s in arg) alist.WriteLine("s1[" + i + "]=" + s1[i]). An application of the ArrayList class is given below.IndexOf(a1.i<alist.Reverse(s1).Length.WriteLine("j = " + j).WriteLine("s1[" + i + "]=" + s1[i]). The method Add() adds an element to the list.Collections. Console.Add(s).3 ArrayList Class An ArrayList is used in situations where we want an array-like list.cs using System. // j = -1 why ? } } 4.i++) { Console. for(int i=0.i<s1. ARRAYLIST CLASS 43 string[] s1 = new string[] { "aaba". class arraylist { public static void Main(string[] arg) { ArrayList alist = new ArrayList(). } int j = Array. using System.3.i<s1.Length. "alla".i<a1. for(int i=0.2).123).WriteLine("a1[" + i + "]=" + a1[i]).i++) { Console.Clear(a1.Count.i++) { Console.Sort(s1). } Array. } Array.4. "baaba".i++) { .Length.

3500500).44 CHAPTER 4. using System.alist[i]).test). removes an element in the dictionary.value) adds an element to the ListDictionary.s1). Console.Write("\n"). population. using System.4 ListDictionary Class The ListDictionary class stores a key and a value.Equals(nlist).Collections. class Dictionary { public static void Main() { ListDictionary population = new ListDictionary(). ArrayList nlist = new ArrayList(). alist.Add("Durban". string s1 = "Xena". The method void Remove(object key).Add("Johannesburg".Collections. Console. population.Add("CapeTown". } Console. The method public void Add(key. } // end main } 4. BUILT-IN CLASSES Console.WriteLine("{0}". foreach(DictionaryEntry name in population) { . population.Count).550500).alist.RemoveAt(1).Specialized. // Dictionary. alist. nlist = alist. bool test = alist.Write("Argument Count:{0}\n".9345120).Insert(3.cs using System.Write("{0}".

GetEnumerator().Key.Write("The elements of the array are: ").6 Mathematics Class and Random Class The Math class is sealed. public class ArrayGetEnumerator { public static void Main() { string[. // Enumerator.cs . all the classes and data members are static.MoveNext()) Console. } } // end Main() } 45 4.] strArry = {{"1". // distance.Write(" {0}". we use the members and methods with the class name. foreach(DictionaryEntry name in population) { Console.IEnumerator for the current instance.Current).name.WriteLine("{0} = {1}". IEnumerator sEnum = strArry. using System.Remove("Durban").WriteLine("{0} = {1}".name.name.5.name."three"}}.sEnum. The Math class also includes two constants. so we cannot create an object of type Math.Value).Collections. Console. } } 4. A sealed class cannot be used for inheritance. {"3".Collections."one"}. PI and E. Instead.cs using System. while(sEnum."two"}.Key. CLASS IENUMERATOR Console. Additionally.4. {"2". } population.5 Class IEnumerator The method public virtual IEnumerator GetEnumerator() returns a System.Value).

ToInt32(line).Convert.ReadLine(). Console. if(dir == ’S’ || dir == ’s’) beta1 = -beta1.source).ReadLine().Convert.ReadLine(). beta1 += temp/60. Console. double alpha1. Console. dest = Console. alpha1 = (double) System.WriteLine("minutes: "). beta2. line = Console.ToInt32(line). dest.WriteLine("W/E: ").ReadLine().ToInt32(line).WriteLine("Enter the name of the destination: "). line = Console.Convert.ReadLine().ReadLine(). string source. beta1 = (double) System. source).0. line = Console.WriteLine("minutes: ").Convert. dir = line[0]. temp = (double) System. Console. Console.46 CHAPTER 4. Console.WriteLine("Enter the latitude of {0}: ". Console.0.WriteLine("degrees: ").WriteLine("degrees: "). temp. line = Console. Console. class Distance { public static void Main() { double r = 6371. line = Console.ReadLine().ReadLine(). Console.WriteLine("Enter the latitude of {0}: ".WriteLine("N/S: "). if(dir == ’E’ || dir == ’e’) alpha1 = -alpha1. line = Console. Console. alpha2.0. . temp = (double) System. BUILT-IN CLASSES using System. beta1. Console. distance. Console.dest).ReadLine().WriteLine("degrees: "). dir = line[0].WriteLine("Enter the longitude of {0}: ". line. alpha1 += temp/60.WriteLine("Enter the name of the source: "). source = Console. theta.ToInt32(line). char dir. line = Console.

PI/180.WriteLine("degrees: ").Cos(beta2)*Math. beta1 *= Math. } } 47 The following table shows a partial list of the Math methods. temp = (double) System.distance).WriteLine("N/S: ").WriteLine("minutes: "). Console.ReadLine(). dir = line[0]. Console.WriteLine("Enter the longitude of {0}: ".Sin(beta2). theta = Math.ToInt32(line).Convert. alpha2 += temp/60.0.dest. dir = line[0]. alpha2 = (double) System. line = Console.ReadLine().0. if(dir == ’E’ || dir == ’e’) alpha2 = -alpha2.Acos(temp).ReadLine().Cos(alpha1-alpha2) + Math.WriteLine("W/E: "). line = Console. line = Console.WriteLine("The distance between {0} and {1} is {2} km". alpha2 *= Math. source.Sin(beta1)*Math. Console.Cos(beta1)*Math. alpha1 *= Math.ReadLine(). distance = r*theta.0. beta2 *= Math. line = Console.PI/180.0. . if(dir == ’S’ || dir == ’s’) beta2 = -beta2. MATHEMATICS CLASS AND RANDOM CLASS beta2 = (double) System.WriteLine("minutes: ").ReadLine().6.dest).Convert.4.Convert.ToInt32(line).ToInt32(line).PI/180.Convert. Console. temp = (double) System.0.ToInt32(line). Console. beta2 += temp/60. Console. Console.PI/180. temp = Math. line = Console.0.

x2) Smaller of the two arguments Pow(x1.i<10.i<10.i++) Console.WriteLine("Random Console.WriteLine("Random for(int i = 0.48 Method Abs(x) Atan(x) Returns Absolute value of x CHAPTER 4.10)").cs using System. x2) Value of x1 raised to the power of x2 Round(x.WriteLine(). . sequence(no seed.int.MaxVal)").limit 0. where x >= 0 Max(x1. x2) Larger of the two arguments Min(x1.. class LearnRandom { public static void Main() { Random r = new Random(). BUILT-IN CLASSES Argument Return Data Type Data Type Overloaded Return matches argument type Double Double Double Double Double Overloaded Overloaded Double Overloaded Double Double Double Double Double Double Return matches argument type Return matches argument type Double Return matches Double Double Double Angle in Radians whose tangent is x Cos(x) Cosine of x where x is in radians Exp(x) Value of e raised to the power of x Log(x) Natural log of x.WriteLine("random Console..Next()).limit 0. no: {0}". y) Value of x rounded to y decimal places Sin(x) Sine of x where x is in radians Sqrt(x) Square root of x where x <= 0 Tan(x) Tangent of x where x is in radians The next program shows an application of the Random class.i++) Console.r.WriteLine("random sequence(no seed. Console.Next(10)). for(int i=0.r. no: {0}". // random.

Console.WriteLine("Random sequence(no seed. // pointt. Console.(float)13.and y.7.WriteLine("The x coordinate is " + xcoord).WriteLine("The y coordinate is " + ycoord).4.WriteLine("Random sequence(no seed.limit 50.i++) Console.r. byte[] b = new byte[5].i++) Console. .Windows.666666666667). for(int i=0.WriteLine("Our Point is: " + p). float ycoordF = pF.Equals(q). The PointF structure represents an ordered pair of floating point x.NextBytes(b).limit 0.Forms.100))...i<b. r.Y.WriteLine("random no: {0}". int ycoord = p.Length. POINT CLASSES 49 Console. Console.WriteLine(" the points are equal: " + b).Next(50.100)").X. Point q = new Point(xcoord.b[i]).NextDouble()).cs using System.WriteLine("The x coordinate is " + xcoordF). Console.X. limit 0.i<10. using System.WriteLine("Our Point is: " + pF). for(int i=0.coordinates that define a point in a two-dimensional plane.3333. Console.1)"). using System.i++) Console.Drawing.WriteLine("random byte: {0}". PointF pF = new PointF((float)23.ycoord).r.WriteLine("Random sequence in byte array(no seed.. } } 4. Console. for(int i=0. float xcoordF = pF. Console.Y.1)").13).WriteLine("random no: {0}".i<10.7 Point Classes The Point structure represents an ordered pair xy of integers. Console. int xcoord = p. class PointTest { public static void Main() { Point p = new Point(23. bool b = p.

50

CHAPTER 4. BUILT-IN CLASSES Console.WriteLine("The y coordinate is " + ycoordF); PointF qF = new PointF(xcoordF,ycoordF); b = pF.Equals(qF); Console.WriteLine(" the points are equal: " + b); }

}

4.8

Class BitArray

For dealing with bit string we use the class BitArray, where 1 is identified with true and 0 is identified with false. The constructor BitArray a = new BitArray(16); sets all elements to false. // BitArrayTest.cs using System; using System.Collections; public class BitArrayTest { static void Main() { BitArray a = new BitArray(16); BitArray b = new BitArray(16); a[3] = a[4] = a[5] = true; b[4] = b[5] = b[6] = true; BitArray c = a.And(b); Console.WriteLine("Bitarray c"); int i; for(i=0;i<16; i++) Console.WriteLine(c[i]); Console.WriteLine(""); BitArray d = (BitArray) c.Clone(); Console.WriteLine("Clone c into d"); for(i=0;i<16;i++) Console.WriteLine(d[i]); BitArray e = a.Not(); Console.WriteLine("Not a");

4.9. OBJECT CLASS for(i=0;i<16;i++) Console.WriteLine("e[" + i + "]=" + e[i]); a.SetAll(true); Console.WriteLine("a.SetAll(true)"); for(i=0;i<16;i++) Console.WriteLine("f[" + i + "]=" + a[i]); BitArray g = d.Not(); for(i=0;i<16;i++) Console.WriteLine("g[" + i + "]=" + g[i]); BitArray f = d.Xor(g); Console.WriteLine("Xor d to get f"); for(i=0;i<16;i++) Console.WriteLine("f[" + i + "]=" + f[i]); } }

51

4.9

Object Class

The Object class supports all classes in the .NET Framework class hierarchy and provides low-level services to derived classes. This is the ultimate superclass of all classes in the .NET Framework; it is the root of the type hierarchy. The C# syntax is [Serializable] public class Object Public static (non-instance) members of this type are safe for multithreaded operations. Instance members are not guaranteed to be thread-safe. Languages typically do not require a class to declare inheeritance from Object since the inheritance is implicit. Since all classes in the .NET Framework are derived from Object, every method defined in the Object class is available in all objects in the system. Derived classes can and do override some of these methods, including Object.Equals - support comparisons between objects Object.Finalize - performs cleanup operations before an object is automatically reclaimed Object.GetHashCode - generates a number corresponding to the value of the object to support the use of a hash table Object.ToString - manufactures a human-readable text that describes an instance of the class

52

CHAPTER 4. BUILT-IN CLASSES

The default constructor is called by derived class constructors to initialize state in this type. Initializes a new instance of the Object class. The method GetHashCode() serves as a hash function for a particular type, suitable for use in hashing algorithms and data structures like a hash table. The method GetType() gets the type of the current instance. The following code compares the current instance with another object. // object1.cs using System; public class object1 { public static void Main() { Object obj1 = new Object(); Object obj2 = new Object(); Console.WriteLine(obj1.Equals(obj2)); // => false obj2 = obj1; Console.WriteLine(obj1.Equals(obj2)); // => true } } The following example shows a Point class that overrides the Object.Equals() method to provide value equality and a class Point3D, which is derived from the Point class. The Object.Equals() method uses Object.GetType() to determine whether the run-time types of the two objects are identical. // object2.cs using System; class Point : Object { protected int x, y; public Point() { this.x = 0; this.y = 0; } public Point(int X,int Y) { this.x = X; this.y = Y; } public override bool Equals(Object obj)

Point3D p4 = new Point3D(5. bool b2 = p3. } public override int GetHashCode() { return x^y. this.9. Console.GetHashCode().8). 53 . } // ^ XOR operation } // end class Point class Point3D : Point { int z. Console.GetHashCode().Equals(p2). return (x == p.6.7).z. OBJECT CLASS { // check for null and compare run-time types if(obj == null || GetType() != obj.y = Y. } } // end class Point3D public class object1 { public static void Main() { Point p1 = new Point(5.6.GetType()) return false. Point p = (Point) obj. Point p2 = new Point(6.int Y. Console.Equals(obj) && z == ((Point3D) obj). Console.9).WriteLine("b1 = " + b1).WriteLine("h2 = " + h2). bool b1 = p1. this.int Z) { this.WriteLine("b2 = " + b2). } public override bool Equals(Object obj) { return base.9).GetHashCode() ^ z. } public override int GetHashCode() { return base.x = X. public Point3D(int X. int h1 = p1. Point3D p3 = new Point3D(5.x) && (y == p.z = Z.Equals(p4). int h2 = p3.4.y).WriteLine("h1 = " + h1).

Console. // object3. i.WriteLine("name = " + m2. CHAPTER 4. m1. public string name.name).e.age). BUILT-IN CLASSES creates a shallow copy of the current object. it returns a shallow copy of the current object.cs using System. } class MyDerivedClass : MyBaseClass { public static void Main() { // create an instance of MyDerivedClass and assign values // to its fields MyDerivedClass m1 = new MyDerivedClass(). Console.MemberwiseClone().name = "John". } } .WriteLine("age = " + m2.54 } } The method protected object MemberwiseClone(). // performs a shallow copy of m1 and assign it to m2 MyDerivedClass m2 = (MyDerivedClass) m1.MemberwiseClone().age = 42. public int age. The following code shows how to copy an instance of a class using Object. class MyBaseClass { public static string CompanyName = "KXK". m1.

mySex. The class also defines a set of functions (also called methods or operations) which can be invoked on its objects.Chapter 5 Object-Oriented Programming 5. An object oriented program is composed of one or more objects. One or more objects (instances) can be created from a class by a process called instantiation. // Person1. Object-oriented programming is essentially programming in terms of smaller units called objects. The Person is described by his name. private char mySex = ’n’.cs using System. myAge. The following program shows an example for class Person. The process of deciding which attributes and operations will be supported by an object (i. private int myAge = 0. Generally the data is hidden within the objects (instances) and can be accessed only through functions defined by its class (encapsulation). age and sex. These private data members are only visible inside the body of class Person1. Thus we have three attributes: myName. defining the class) is called abstraction. The term passing a message to an object means invoking its operation. Sometimes the set of operations supported by an object is also referred to as the interface exposed by this object. 55 . We say the state of the object is defined by the attributes it supports and its behaviour is defined by the operations it implements. Each object holds some data (fields or attributes) as defined by its class. class Person1 { private string myName = "N/A".1 Write your own class In CSharp we can write our own class.e.

} set { myAge = value.int age. OBJECT-ORIENTED PROGRAMMING // default constructor public Person1() { } // constructor public Person1(string name. } set { mySex = value. } public override bool Equals(object o) { if((myName==((Person1) o).myName) && (myAge==((Person1) o).myAge) && (mySex==((Person1) o). Sex = " + Sex.mySex)) return true. else return false.myName = name. } } public char Sex { get { return mySex.mySex = sex.56 CHAPTER 5. } . this. this. } set { myName = value.myAge = age. Age = " + Age + ". } // declare a Name property of type string public string Name { get { return myName.char sex) { this. } } public override string ToString() { return "Name = " + Name + ". } } public int Age { get { return myAge.

namely public string get_Name() .7. person3. The CSharp compiler translates for example the Name property to a pair of methods.Sex = ’m’.1.’f’). WRITE YOUR OWN CLASS public static void Main() { // create a new Person object using default constructor Person1 person1 = new Person1(). Console. person1. person3. mySex. bool same = person2.WriteLine("name of person[0]: " + pmany[0].23. person2.WriteLine("same person = " + same). myAge.Name = "Joe".’m’).WriteLine("sex of person[1]: " + pmany[1].myName). and Sex. person1. Person1 person2 = new Person1().person3). // Set some values on the person object person1. person2.Name = "Jane".{0}".WriteLine("Person details . To access these variable outside the class we use the special property methods Name. Console. Console.{0}".myName). // array of persons Person1[] pmany = new Person1[2].42. person2.Age = 31. Person1 person3 = new Person1(). Age.Age = 99.mySex).person1).WriteLine("Person details . These variable are visible only inside the body of class Person1.Name = "Jane".’m’).person2).WriteLine("Person details: " + person4. Console.mySex).Equals(person3). pmany[0] = new Person1("Carl". pmany[1] = new Person1("Ola".WriteLine("Person details: " + person4.Age = 31. Console. Console.5.Sex = ’f’. Console. } // end Main } 57 class Person1 defines three private member variables. Person1 person4 = new Person1("otto". person3.Sex = ’f’. Console.{0}". myName.WriteLine("Person details .

} The class Person1 contains the Main() method. this. } } public int Age { get { return myAge. this.58 { return myName.cs using System. The file Person.myName = name. OBJECT-ORIENTED PROGRAMMING public void set_Name(string value) { myName = value. public char mySex = ’n’. } // declare a Name property of type string public string Name { get { return myName. // default constructor public Person() { } // constructor public Person(string name.int age.char sex) { this. } } public char Sex .cs only contains the class Person and no Main() method.mySex = sex. public int myAge = 0. // Person. class Person { public string myName = "N/A".myAge = age. } set { myName = value. In some application it would be better to keep the class Person1 without the Main() method and have an extra file which calls the Person objects. } CHAPTER 5. } set { myAge = value.

1. person2.Age = 31. Person person2 = new Person(). person1.WriteLine("Person details . } public override bool Equals(object o) { if((myName==((Person) o). Age = " + Age + ".cs The file PersonMain. } } public override string ToString() { return "Name = " + Name + ".cs using System. person1.Sex = ’m’. // Set some values on the person object person1.myName) && (myAge==((Person) o). 59 .{0}". Console. class PersonMain { public static void Main() { // create a new Person object using default constructor Person person1 = new Person(). WRITE YOUR OWN CLASS { get { return mySex.person1).cs contains the Main() method. Sex = " + Sex. // PersonMain.Name = "Jane".5. person2.myAge) && (mySex==((Person) o). } } To generate the Person.dll file we run csc /t:library Person. else return false.Name = "Joe". } set { mySex = value.Age = 99.mySex)) return true.

dll PersonMain. Console. object Clone() When we write our own class in most cases we should override the methods string ToString(). we can also use the short-cut csc Person.WriteLine("Person details: " + person4.60 CHAPTER 5. Person person3 = new Person(). pmany[0] = new Person("Carl". Console.WriteLine("name of person[0]: " + pmany[0]. 5.person3).person2). Console.{0}". bool same = person2. } // end Main } To get the PersonMain.myName).exe file.’f’).Age = 31.WriteLine("person3 new age: " + person3.mySex).Sex = ’f’.7. pmany[1] = new Person("Ola".WriteLine("same person = " + same).WriteLine("Person details .23. OBJECT-ORIENTED PROGRAMMING person2.cs to generate the PersonMain.Name = "Jane". // array of persons Person[] pmany = new Person[2]. // increment the age of person3 person3. person3.exe file we run csc /r:Person.42.2 Override Methods bool Equals(). Person person4 = new Person("otto".WriteLine("Person details: " + person4.cs PersonMain.Age). Console.WriteLine("sex of person[1]: " + pmany[1].{0}".Equals(person3). Console.cs However.mySex). Console. Console.’m’).’m’). Console.Age++.WriteLine("Person details . person3. An example is given below .myName).Sex = ’f’. person3.

double z) = x. } public object Clone() { object o = new Point3D(X.Z).Point3D p2) { return (p1. = z.double y. else return false.Y-p2.X) && (Y==((Point3D) o).5.Z-p2.X.Z)*(p1.X)+(p1.Z } Point3D(double x.Z).X)*(p1.{1}. OVERRIDE METHODS // Point3D.Y. } public override bool Equals(object o) { if((X==((Point3D) o).Z)) return true. } public override string ToString() { return String.Y)+(p1. public double Z.Y)*(p1.{2})". = y.Z-p2. } } An application of this class is . 61 // square of distance between two Points public double distance(Point3D p1.X-p2.2.Format("({0}.Y.Z).Y) && (Z==((Point3D) o). public Point3D() { } // default constructor public { this. public class Point3D { public double X. public double Y.cs using System.Y this.X-p2. return o.Y-p2.X this.

double y = 3.Equals(p2). Console.c).1. Console. OBJECT-ORIENTED PROGRAMMING public class Point3DMain { public static void Main() { double x = 2. In the next program we use inheritence.y.1.0. Point3D p2 = new Point3D(a.5. double d = q.m.z). double n = 7. First we must declare our intention to use Vehicle as the base class of Car. double k = 2. } } 5.0.62 // Point3DMain. The class Car is derived from class Vehicle. Point3D p4 = new Point3D(0. double a = 2.0.5.0). double m = 1.WriteLine("p4 = " + p4).0. CHAPTER 5.cs using System.0. Point3D q = new Point3D().WriteLine("d = " + d).WriteLine("p1 = " + p1).3 Inheritance Inheritance is one of the primary concepts of object-oriented programming. double z = 4.5.1. double c = 4.WriteLine("r = " + r). Point3D p3 = new Point3D(k. It allows us to reuse existing code. This is accomplished through the Car class declaration public class Car : Vehicle . Point3D p1 = new Point3D(x. In the class Car we use code from the class Vehicle. bool r = p1.n).1. // type conversion Console. Console.b. double b = 3.0.distance(p1.Clone().p3). p4 = (Point3D) p3.

weight).int aTopSpeed. price = aPrice. } public virtual void print() { Console. private int topSpeed. private double price.cs using System. and the keyword base call the base class constructor. } public int getWeight() { return weight. public Vehicle() {} public Vehicle(int aWeight.WriteLine("Top Speed: {0} km/h". Console. C# supports single class inheritance only.3. Console. int horsepower.int aTopSpeed. } } // end class Vehicle class Car { private private private : Vehicle int numberCylinders. . int displacement. // MVehicle. } public double getPrice() { return price. public Car() { } public Car(int aWeight.double aPrice.double aPrice) { weight = aWeight.topSpeed). topSpeed = aTopSpeed. INHERITANCE 63 Then the colon. class Vehicle { private int weight.int aNumberCylinders.WriteLine("Price: {0} Dollar".5. : .} public int getTopSpeed() { return topSpeed.price).WriteLine("Weight: {0} kg".

6. which must provide an implementation for each interface member defined. The following program shows an example. methods.displacement). // Policies.horsepower). they must define a contract.WriteLine(""). and/or properties.120.WriteLine("Cylinders: {0} ". } public int getDisplacement() { return displacement. indexers. The reason interfaces only provide definitions is because they are inherited by classes and structs. } public override void print() { base. The only thing it contains are definitions of events. Since interfaces must be defined by inheriting classes and structs. } public int getHorsepower() { return horsepower. Console.aPrice) { numberCylinders = aNumberCylinders.cs public interface Policy . Console. aVehicle.WriteLine("Diplacement: {0} cubic cm". Console.WriteLine(""). Console.30000.100.00. but has no implementation.aTopSpeed.64 CHAPTER 5. horsepower = aHorsepower.300).numberCylinders). Console.12000.print().print(). displacement = aDisplacement.00). } } An interface looks like a class. OBJECT-ORIENTED PROGRAMMING int aHorsepower. Console. } } class myCar { public static void Main() { Vehicle aVehicle = new Vehicle(15000. aCar.120.WriteLine("Horsepower: {0} ". Car aCar = new Car(3500. } public int getNumberCylinders() { return numberCylinders.int aDisplacement) : base(aWeight.print(). Console.Write("A vehicle: ").Write("A car: ").

cs Using reflection we can also create an instance of a class and invoke its member methods at runtime. We compile investment.dll via csc /t:library Policies.cs to create Policies.int n) { return (p < 25000. This feature can be used to write more generic (dynamically extensible) programs which receive names of classes at runtime. All policy classes implement the Policy interface except GoldPolicy which defines Rate without implementing policy. } } 65 Each policy provides a Rate method which returns the rate of interest for a given principal and for a given period. } } public class SilverPolicy : Policy { public double Rate(double p.int n) { return 7.int period). and args[2]. INHERITANCE { double Rate(double principal.5. } } public class GoldPolicy { public double Rate(double p. if(n >= 3) r += 1. period and policy name as arguments args[0].3. } } public class PlatinumPolicy : Policy { public double Rate(double p. The investment.0) ? 8 : 10.0) ? 10 : 12. } public class BronzePolicy : Policy { public double Rate(double p.cs program including Main accepts principal.int n) { return (n < 5) ? 9 : 11. We compile Policies.cs as .int n) { double r = (p < 50000. args[1]. return r.

investment 60000 5 SilverPolicy. We overload the method max() to find the maximum of numbers. double r = pol.CreateInstance(t).amount).cs using System.n).66 CHAPTER 5. class Investment { public static void Main(string[] args) { double p = Double. Console. Policy pol = (Policy) Activator. The methods of a class may have the same name if they have different numbers of parameters. public class Maximizer { public class Maximum { public static double max(double p. or if they have different parameter kinds.Reflection.n).Pow(1.4 Overloading Methods Methods in a class can be overloaded.WriteLine("you will get {0:#.0. OBJECT-ORIENTED PROGRAMMING csc /r:Policies.00}". for example.cs using System.GetType(args[2]).Rate(p. using System.Parse(args[0]). or if they have different parameter types.Policies // investment. // methods.double q) { . // string to int Type t = Type.dll investment.Parse(args[1]). // string to double int n = Int32.cs We would execute the program. double amount = p*Math. } } 5.0+r/100.

r).9)).max(4. \.int.1. } public static double max(double p. } return max. array[0] = 3.int) to the program that find the maximum of four integer numbers. Console. OPERATOR OVERLOADING if(p > q) return p.cs using System.4. [] In the next program we overload + to add two complex numbers.5 Operator Overloading Operators can be overloaded (operator overloading) such that +.5.max(3.5 and 4.7)). Console.4.q). // Complex.WriteLine("maximum of 4.double r) { return max(max(p.9 is {0}". foreach(double val in list) { if(val > max) max = val. } public static double max(double[] list) { if(list. array[3] = 2.1. } 67 public static void Main(string[] args) { Console.7 is {0}". 2.5. array[1] = 5.WriteLine("maximum of 3. 5. } // end main } } Exercise. %. array[2] = 3. Add a method max(int. return q. double max = list[0]. -.9. 4.Length == 0) return 0. *.double q. double[] array = new double[4].1.4. .1.5.7.int.max(array)).WriteLine("maximum element in array = {0}".2.4.

. There is no inheritance for structure.0. OBJECT-ORIENTED PROGRAMMING public class Complex { public double real.imag). // real part of complex number // imaginary part of number public Complex(double real. 5. r1 = r1 + r2. Console. // enumeration. this. public double imag.real.r1. Structures do not contain methods.0). Complex r2 = new Complex(2.1.imag = imag.imag + c2.0).2.real = c1. The multiplication of two complex numbers z1 = a + ib and z2 = c + id (with a. Overload in the program also * for the multiplication of two complex numbers.6 Structures In CSharp we can also use structures.real + c2.imag = c1.real. } } Exercise. b. } } class ComplexMain { public static void Main() { Complex r1 = new Complex(1.0. } public static Complex operator + (Complex c1. return c1. d real) is given by z1 ∗ z2 = a ∗ c − b ∗ d + i(ad + bc).imag.WriteLine("Real: {0} Imaginary: {1}i".r1. The program also shows how enumeration can be used.real = real.double imag) { this.68 CHAPTER 5. c. c1.cs using System.Complex c2) { c1. The objects are stored on the stack compared to classes which are stored on the heap.

a.Name. We can pass both static and instance methods. a.Age = 17. DELEGATES 69 enum MemberType { Lions. // new copy of a is assigned to b b. C# delegates are implemented in the . .Name = "John". We can pass method m in class A.Age remains 13 Console. Thus the use of delegates involves four steps.NET framework as a class derived from System. 1. a. // a.Group = MemberType. Jackals.Age = 13.7 Delegates A delegate in C# allows us to pass methods of one class to objects of other classes that can call those methods. to class B and class B will be able to call method m in class A. Elefant.Delegate. Define all the methods whose signature match the signature of the delegate object that we have defined in step 1. Dogs }. Call the encapsulated methods through the delegate object. Declare a delegate object with a signature that exactly matches the method signature that we are trying to encapsulate. // Value types are automatically initialized a. The following C# program shows the above four steps.WriteLine("Member {0} is {1} year old and belongs to group of {2}". public MemberType Group. 3.5.Eagles. wrapped in a delegate. 4.a. Create delegate object and plug in the methods that we want to encapsulate.7.Group). ClubMember b = a. public int Age. } class enumeration { public static void Main(string[] args) { ClubMember a. Eagles. a.Age. struct ClubMember { public string Name. 2. This concept is familiar to C++ where one uses function pointers to pass functions as parameters to other methods in the same class or in another class. } // end main } 5.

} } // end class Class3 . Declare a delegate with the signature of the // encapsulated method public delegate void MyDelegate(string input). CHAPTER 5. return d3. } } // end class Class1 // Step 3. MyDelegate d3 = d1 + d2.WriteLine("delegateMethod2: the input to the method is {0}". Call the encapsulated method through the delegate class Class3 { public void callDelegate(MyDelegate d. } } // end class Class2 // Step 4.70 // Delegate.input). Define methods that match with the signature // of delegate declaration class Class1 { public void delegateMethod1(string input) { Console. OBJECT-ORIENTED PROGRAMMING // Step 1.delegateMethod2). MyDelegate d2 = new MyDelegate(c2.WriteLine("delegateMethod1: the input to the method is {0}". Create delegate object and plug in the methods class Class2 { public MyDelegate createDelegate() { Class1 c2 = new Class1().delegateMethod1).input).string input) { d(input). MyDelegate d1 = new MyDelegate(c2.cs using System. // Step 2. } public void delegateMethod2(string input) { Console.

public string LastName = null.FirstName. } } // end method CompareNames() . } public static int CompareFirstNames(object name1.cs using System.5.object obj2)."calling the delegate").n2) > 0) { return 1. } else if(string. // MyDelegate. DELEGATES 71 class Driver { public static void Main() { Class2 c2 = new Class2().n2) < 0) { return -1. LastName = last.Compare(n1. // type conversion if(string.7. public class Name { public string FirstName = null. // type conversion string n2 = ((Name) name2).Compare(n1. } else { return 0. Here we use delegates to compare strings.object name2) { string n1 = ((Name) name1). MyDelegate d = c2. } // end Main } The output is: delegateMethod1: the input to the method is calling the delegate delegateMethod2: the input to the method is calling the delegate Another example is given below.string last) { FirstName = first. // this is the delegate declaration public delegate int Comparer(object obj1. Class3 c3 = new Class3().FirstName.callDelegate(d. c3. public Name(string first.createDelegate().

"Cooper"). OBJECT-ORIENTED PROGRAMMING public override string ToString() { return FirstName + " " + LastName.i<names.Sort(cmp).PrintNames()."Smithlone"). // observe the delegate argument sd."Jones").72 CHAPTER 5.i++) { for(int j=i.names[j])>0) .WriteLine("\nBefore Sort:\n").WriteLine("\nAfter Sort:\n"). names[3] = new Name("Ola".Length. sd. } public void Sort(Comparer compare) { object temp."Xenon").CompareFirstNames). } } // end class Name class SimpleDelegate { Name[] names = new Name[4]. sd.j<names. for(int i=0. // the delegate instantiation Comparer cmp = new Comparer(Name. Console. names[1] = new Name("Carl". public SimpleDelegate() { names[0] = new Name("John". PrintNames().Length. Console. } static void Main() { SimpleDelegate sd = new SimpleDelegate().j++) { // using delegate "compare" just like a normal method if(compare(names[i]. names[2] = new Name("Rolf".

5.7.ToString()). } } // end method PrintNames() } 73 . DELEGATES { temp = names[i]. names[j] = (Name) temp. names[i] = names[j]. foreach(Name name in names) { Console.WriteLine(name.WriteLine("Names:\n"). } // end if } } } // end method Sort public void PrintNames() { Console.

A byte is 8 bits. The Stream class and its subclasses provide a generic view of data sources and repositories. Writing is the transfer of data from a data structure into a stream. 74 .IO. Seeking is the query and modifying of the current position within a stream. long. char and also the data type string and StringBuilder to a stream (binary file manipulation). Reading is the transfer of data from a stream into a data structure.Chapter 6 Streams and File Manipulations 6. 3) Streams can support seeking. double. float. short.BinaryWriter and System. int.IO. such as an array of bytes. bool.1 Introduction A stream is a sequence of bytes. Streams involve the following three operations: 1) Streams can be read from. 6. isolating the programmer from the specific details of the operating system and underlying devices.2 Binary File Manipulations System.BinaryReader can be used for writing and reading primitive data types byte. 2) Streams can be written to.

using System.Text.{3}".Write(i). char c = br. class BinaryIO1 { private static void WriteData(int i.WriteLine("{0}.Write(c). ReadData().bool b) { Stream s = File.cs using System.IO.cs using System.OpenRead("info. br.true).b).Close().IO.i. bw.char c. Console. bw. s.OpenWrite("info. using System.dat").Write(d). int i = br.Text. bool b = br.2.Write(b).ReadChar(). s.{2}.3. } public static void Main(string[] args) { WriteData(12345. } } // BinaryIO2. BINARY FILE MANIPULATIONS // BinaryIO1.’y’. using System.d. BinaryWriter bw = new BinaryWriter(s). double d = br. } private static void ReadData() { Stream s = File.double d.6.dat").c.ReadDouble().ReadBoolean().Close(). 75 .ReadInt32().Close(). bw. BinaryReader br = new BinaryReader(s).{1}. bw.14159.Close(). using System. bw.

ToString()).Write) and the asynchronous methods FileStream.dat"). BinaryReader br = new BinaryReader(s). string sb = br. but . br.StringBuilder sb) { Stream s = File. The FileStrean class can open a file in one of two modes.Write(sb. as well as other file-related operating system handles (including pipes.WriteLine("{0}.BeginRead and FileStream. s.Close(). Both sets of methods will work in either mode. string t = br. Console.Close(). and so on).Close().sb). ReadData().Read and FileStream.ReadString().BeginWrite). WriteData("Hello Egoli". bw. // write length-prefixed string bw.dat").t. BinaryWriter bw = new BinaryWriter(s).3 Text File Manipulation Reading a text file.Write(t). however. } public static void Main(string[] args) { StringBuilder sb = new StringBuilder("Hello World!").{1}". } } 6.76 CHAPTER 6.ReadString(). standard input.Close(). with signigicant performance consequences for the synchronous methods (FileStream. s. STREAMS AND FILE MANIPULATIONS class BinaryIO2 { private static void WriteData(string t.OpenWrite("info. FileStream buffers input and output for better performance. } private static void ReadData() { Stream s = File. bw. the mode will affect the performance of these methods.sb). FileStream defaults to opening files synchronously.OpenRead("info. standard output. The class FileStream is useful for reading and writing files on a file system. either synchronously or asynchronously.

6.3. TEXT FILE MANIPULATION

77

provides a constructor to open files asynchronously. FileStream objects support random access to files using the FileStream.Seek method. The Seek method allows the read/write position to be moved to any position within the file. This is done with byte offset reference point parameters. The byte offset is relative to the seek reference point, which can be the beginning, the current position, or the end of the underlying file, as represented by the three properties of the SeekOrigin class. We convert the array of bytes into an ASCII text for displaying it on the console. // readfile.cs using System; using System.IO; using System.Text; // for encoding class ReadFile { public static void Main(string[] args) { Stream s = new FileStream(args[0],FileMode.Open); int size = (int) s.Length; byte[] buffer = new byte[size]; s.Read(buffer,0,buffer.Length); s.Close(); string text = Encoding.ASCII.GetString(buffer); Console.WriteLine(text); } } Writing to a file (text mode). We append the text provided by the line string text = "all the good men and women" + "\r\n"; to the file provided by args[0]. // writefile.cs using System; using System.IO; using System.Text; // for encoding class WriteFile { public static void Main(string[] args) { Stream s = new FileStream(args[0],FileMode.Append,FileAccess.Write);

78

CHAPTER 6. STREAMS AND FILE MANIPULATIONS string text = "all the good men and women" + "\r\n"; // append end // of line characters byte[] buffer = Encoding.ASCII.GetBytes(text); s.Write(buffer,0,buffer.Length); s.Close(); // also flushes the stream }

} Writing the date and time into a file using the DateTime class.. // placeorder.cs using System; using System.IO; class PlaceOrder { public static void Main(string[] args) { DateTime dt = DateTime.Now; string today = dt.ToString("dd-MMM-yyyy"); string record = today + "|" + String.Join("|",args); StreamWriter sw = new StreamWriter("order.txt",true); sw.WriteLine(record); sw.Close(); } } The useful classes in reading/writing text files are: StreamReader and StreamWriter. Given the file datain.txt with the two lines Green 4750 3000.40 Bakley 3451 2800.50 the following program reads the file line by line and displays it on the Console and also writes it to the output file dataout.txt. // Filemanipulation.cs using System; using System.IO; class FileManipulation { static void Main(string[] args) {

6.4. BYTE BY BYTE MANIPULATION FileInfo fr = new FileInfo(@"c:\csharp\datain.txt"); StreamReader reader = fr.OpenText(); string sline; string[] substrings; char[] separators = { ’ ’,’,’,’\t’ }; string name; int ID; float gpa; StreamWriter writer = new StreamWriter(@"c:\csharp\dataout.txt",false); sline = reader.ReadLine(); while(sline != null) { substrings = sline.Split(separators,3); name = substrings[0]; ID = int.Parse(substrings[1]); gpa = float.Parse(substrings[2]); Console.WriteLine("{0} {1} {2}",name,ID,gpa); writer.WriteLine("{0} {1} {2}",name,ID,gpa); sline = reader.ReadLine(); } writer.Flush(); writer.Close(); } }

79

6.4

Byte by Byte Manipulation

For reading and writing bytes we use the methods ReadByte() and WriteByte(). The type conversion to char is necessary in the following program. What happens if we remove (char) ? // BytebyByte.cs using System; using System.IO; public class BytebyByte { public static void Main(string[] args) { FileStream s = new FileStream(args[0],FileMode.Open,FileAccess.Read, FileShare.Read); BufferedStream bs = new BufferedStream(s); while(bs.Length > bs.Position)

Create).Open).Close(). class TestFile { static void Copy(string from.FileMode. sin. } } . } } public static void Main(string[] arg) { Copy(arg[0].ReadByte().IO.ReadByte().SeekOrigin. } } bs.WriteLine("--file {0} not found". using System. } catch (FileNotFoundException e) { Console. s. // TestFile.Close(). STREAMS AND FILE MANIPULATIONS { Console. sout.Close(). FileStream sout = new FileStream(to.0). } In the following example we copy byte by byte a file into another file. } sin.e. while(ch >= 0) { sout.cs using System.FileMode.ReadByte()).80 CHAPTER 6.string to.FileName).Write((char) bs.WriteByte((byte) ch).arg[1].Seek(pos.Begin). // type conversion ch = sin.int pos) { try { FileStream sin = new FileStream(from. int ch = sin.Close().

Open. class Oops { public static void Main() { char cl = ’{’. if(ch == cl) countcl++. while(bs.FileMode. .dat". 6. This string of bytes contains all of the information that was held in the object started with.Position) { char ch = (char) bs.IO. int countcr = 0. stored within memory into a linear sequence of bytes.WriteLine("countcl = " + countcl). or a connected graph of objects (a set of objects with some set of references to each other). } // end while fin.Length > bs. BufferedStream bs = new BufferedStream(fin).cs using System.5 Object Serialization Often we want to store a complete object in a stream.cs using System. char cr = ’}’.WriteLine("countcr = " + countcr). } // end Main } Exercise. OBJECT SERIALIZATION In the next program we count the number of curly brackets in a file. Console. // employee. // Oops1. Extend the program so that it also counts the number of rectangular brackets (left and right) and parentheses (left and right).ReadByte().5. By serialization we mean converting an object.Close().Read). if(ch == cr) countcr++. int countcl = 0. Console. This is achieved by a process called object serialization.6. using System.FileAccess. 81 FileStream fin = new FileStream("data.

public double Salary. [Serializable] public class Employee { public string Name. using System. STREAMS AND FILE MANIPULATIONS using System.Serialization.Formatters.Name. // binsertest1.IO.Job.Runtime. } } // end class Employee end file In the following program we apply now object serialization to Employee.Salary). using System.Serialization.Object.Runtime.Serialize(s. // This method is invoked whenever an Employee object // is to be converted to a string public override string ToString() { return String. s. Salary = salary.double salary) { Name = name.bin").string job.Format("{0} is a {1} and earns {2}". public string Job.Close().cs using System. private static void WriteEmployee(Employee emp) { Stream s = File. class BinarySerializatioTest1 { static BinaryFormatter bf = new BinaryFormatter().82 CHAPTER 6. bf. public Employee(string name.Binary. Job = job. } public Employee() { } // we override the ToString() method of System.OpenWrite("emp. } .emp).

<?xml version="1. Employee emp = (Employee) bf.salary) about employees. WriteEmployee(emp).OpenRead("emp. } } 6. s.6. XML DOCUMENTS 83 private static void ReadEmployee() { Stream s = File.WriteLine(emp).0"?> <employees> <employee id="101"> <name> John </name> <job> manager </job> <salary> 72000 </salary> </employee> <employee id="102"> <name> Jane </name> <job> steno </job> <salary> 23000 </salary> </employee> <employee id="103"> <name> Jim </name> <job> salesman </job> <salary> 36000 </salary> </employee> <employee id="104"> <name> Jill </name> <job> clerk </job> <salary> 45000 </salary> </employee> .bin"). job.Close().name. Console. // displays emp.6.ToString() } public static void Main(string[] args) { Employee emp = new Employee("Jack".NET framework provides an XML parser for reading and modifying XML documents. Given below is the file emp.xml containing information (id.6 XML Documents The ."Clerk". There are five employees. ReadEmployee().44000).Deserialize(s).

} } } The program addemp. STREAMS AND FILE MANIPULATIONS <employee id="105"> <name>Jeff</name> <job>CEO</job> <salary>105000</salary> </employee> </employees> The program listemp.sal).Xml.cs takes informations from the command line (id.WriteLine("{0}\t{1}". Console. using System. job.84 CHAPTER 6. and salary of each employee in the file emp. salary) and makes a new entry in the file emp.Value. name. // addemp. class ListEmployees { public static void Main() { XmlDocument doc = new XmlDocument(). // obtain value of salary subtag of the employee tag string sal = emp["salary"].Load("emp.FirstChild.cs using System.cs using System.cs displays id.id.Xml.xml in XmlDocument doc. class AddEmployee { public static void Main(string[] args) .xml").Value. // load employee. foreach(XmlNode emp in list) { // obtain value of id attribute of the employee tag string id = emp.GetElementsByTagName("employee").Attributes["id"]. using System.xml.xml. // listemp. // obtain a list of all employee element XmlNodeList list = doc.

// create a new employee element and value of its attribute XmlElement emp = doc.""). job. sal. // make name tag a subtag of newly created employee tag emp. XmlNode job = doc.InnerText = args[3]. emp.Save("emp."name".InnerText = args[1].SetAttribute("id". XmlNode sal = doc. XML DOCUMENTS { XmlDocument doc = new XmlDocument().AppendChild(name).xml")."job".AppendChild(job).args[0]). name.6. } } We execute the program with (for example) addemp 105 willi president 50000 85 .CreateElement("employee").CreateNode("element". emp.xml").CreateNode("element"."salary"."").Load("emp. // create a name tag and st its value XmlNode name = doc. // save the modified document doc.AppendChild(emp). emp. // add the newly created employee tag to the root (employees) tag doc.AppendChild(sal).InnerText = args[2].""). doc.CreateNode("element".6.DocumentElement.

We can easily update the above program to render other graphical shapes like Rectangle.float x.int X. DrawLine(). The Graphics object provides methods for drawing a variety of lines and shapes.e.1 Drawing Methods The Windows.float y. a Brush object is required. The method DrawEllipse() is given by DrawEllipse(System. Ellipse. The System. or using user-defined gradient or image textures. 86 .Drawing namespace provides access to GDI + basic graphics functionality. open curves. etc.int Y) The first argument is a string. DrawPie(). To fill in an area.float width. DrawPolygon(). The last two arguments is the position where we put the string.Font. i.float height) Every method in the Graphics class has to be accessed by creating an object of that class. All we have to do is to apply the relevant methods appropriately. The drawing methods are DrawString(). Lines.Brush.Chapter 7 Graphics 7.Drawing.Forms namespace contains classes for creating Windows based applications. Using DrawImage() we can display an image. DrawArc() and DrawImage(). In this namespace we find the Form class and many other controls that can be added to forms to create user interfaces. DrawRectangle(). The method DrawString() takes five arguments DrawString(string. DrawEllipse(). the text we want to display. such as a rectangle or a closed curve. and outline shapes are created using a Pen object.Pen. Simple or complex shapes can be rendered in solid or transparent colors.

The following program shows how do draw two triangles using this method.y). new Point(x. new Point(x.new Font("Verdana". 40.Tomato). The Brush is applied for filling shapes such as SolidBrush and HatchStyleBrush.DrawRectangle(new Pen(Color. g.new SolidBrush(Color.40).new Point(x.new Point(x.PaintEventArgs e) { Graphics g = e. } private void f1_paint(object sender.Graphics.y). using System.new Point[]{ new Point(x.Drawing. . we can change the unit of measurement to Inch and Millimeter.3).150.100). using System.1.y).y)}).DrawString("Hello C#". g. DRAWING METHODS 87 Using the Pen class we can specify colour of the border and also the thickness. The Pen class is applied for drawing shapes.new Point(x.Forms.7.y).20).Paint += new PaintEventHandler(f1_paint).cs using System.20.y).Pink. } } The method DrawPolygon(System. The default Graphics unit is Pixel.Drawing.20. draws a polygon for a given set of points. } public static void Main() { Application. public class Hello : Form { public Hello() { this. // HelloGraphics. By applying the PageUnit property.Windows.Pen.Run(new Hello()).

Run(new Triangle()).Graphics.PaintEventArgs e) { Graphics g = e. FillEllipse(Brush.Forms.new Point(250.float x.new new g.cs using System. CHAPTER 7. Pen pen1 = new Pen(Color.cs using System.155). using System. using System.Green. // Fill. g.float height.Forms.new Point(250. Point(250.float height). } } The following program shows how to use FillRectangle(Brush.new new } Point[]{new Point(150.float x.Blue.2).DrawPolygon(pen2. FillPie(Brush. Pen pen2 = new Pen(Color. float width. public class Fill : Form { public Fill() .50).float width.150)}). using System.float width.155).2).150).Drawing.float y. } public void draw_triangle(Object sender.float angleX. using System.Windows.Windows.float y. public static void Main() { Application.float x. Point(50.Paint += new PaintEventHandler(draw_triangle).float height).float angleY). GRAPHICS class Triangle : Form { public Triangle() { this.Drawing.DrawPolygon(pen1.float y. Point[]{new Point(50.255)}).88 // MyPolygon.

255. using System.Blue). g. using System. The alpha-value is implicit 255 (no transparency). Alpha is also known as transparency where 255 is totally solid and 0 is totally transparent.Red). Blue.255. Black.Drawing.FillEllipse(new SolidBrush(Color. public class Draw : Form { public Draw() { } // default constructor protected override void OnPaint(PaintEventArgs e) .green.Graphics. Pink. // draw.FillPie(new SolidBrush(Color.40.0).FromArgb(0. } } 89 7.green.red.90).2.100.50.200.blue) we call for example Color myColor = Color. COLOR CLASS { this. g. Red.Paint += new PaintEventHandler(fillpaint). g.FromArgb(51.150).200. To create a Color structure from the specified 8-bit Color (red.Yellow). } public static void Main() { Application.125).Windows.50.150.cs using System.15.Run(new Fill()).0. } private void fillpaint(object sender.Forms.120).40.7.15. Green.blue) we call for example Color myColor = Color.FillRectangle(new SolidBrush(Color. To create a Color structure from the four ARGB component (alpha.PaintEventArgs e) { Graphics g = e.2 Color Class The Color class provides “constants” for common colors such as White.0.

PointF pointF = new PointF(30.FromArgb(51. myPen.Forms. First we have to create an object of ColorDialog class ColorDialog cd = new ColorDialog().45.Run(new Draw()).Windows.15.255.50)).Click += new EventHandler(b_click).Graphics.45. TextBox tb = new TextBox().GraphicsUnit. } } In C# the user can choose a color by applying the ColorDialog class appropriatly.30.0.DrawString ("Hello". An example is given in the followsing program // ColorD.20).Controls. Pen myPen = new Pen(Color.65). GRAPHICS { FontFamily fontFamily = new FontFamily("Times New Roman"). SolidBrush solidbrush = new SolidBrush(Color. Font font = new Font(fontFamily. ColorDialog clg = new ColorDialog().pointF).Graphics. using System.Width = 50.87.Drawing.FontStyle.cs using System.font. using System.1.90 CHAPTER 7.45.Graphics.Bold.Location = new Point(50.Graphics.40.new Rectangle(33. public class ColorD : Form { Button b = new Button().Pixel).0)).30.DrawBezier(myPen. e. tb. . e.50).30.Red).10). e. public ColorD() { b. b.solidbrush.Add(b).DrawLine(myPen.1.15.Text = "OK". e. } public static void Main() { Application.24. this.DrawEllipse(myPen.

class WinHello : Form { private Button bnclick.Controls. the Click member can only be used on the left-hand side of the += and -= operators.24).Text = "Click.ComponentModel. public WinHello() { Text = "Hello World". the Click member is exactly like a private field of type EventHandler. System. bnclick. outside the Button class.BackColor = clg. System. .3 Button and EventHandler The Button class defines a Click event of type EventHandler. Size = new Size(400.Add(tb). tb. BUTTON AND EVENTHANDLER this. Inside the Button class.3.Drawing.cs using using using using System. } public static void Main(string[] args) { Application.ShowDialog(). bnclick. } } 91 7.60).Add(bnclick). } public void b_click(object sender.400).Run(new ColorD()).Size = new Size(60.Forms.Location = new Point(20.EventArgs e) { clg.Color. The operator += adds a handler for the event. // Winhello. System.Me". Controls. bnclick.Click += new EventHandler(bnclick_Click). Closing += new CancelEventHandler(WinHello_Closing). bnclick = new Button(). bnclick.Windows. However.7. and the -= operator removes a handler for the event.

. = new TextBox(). } // Initialize the main thread // using Single Threaded Apartment (STA) model public static void Main() { Application. MessageBoxButtons. The following program gives an example // Fonts.Forms. } private void WinHello_Closing(object sender. this.Click += new EventHandler(b_click).MessageBoxIcon.Windows. } } We can create a Font selection dialog box using the FontDialog class.CancelEventArgs ev) { if(MessageBox. using System.Run(new WinHello()). this.MessageBoxIcon.OK. public class { Button b = TextBox tb FontDialog Fonts : Form new Button().Show("Hello Egoli!!!!".Drawing."Button Clicked". flg = new FontDialog(). public Fonts() { b.Location = new Point(50.Controls.Cancel = true. MessageBoxButtons.Information).Show("Are you sure?". GRAPHICS private void bnclick_Click(object sender."Confirm exit".YesNo. using System.Text = "OK".Controls.50).92 } CHAPTER 7.Question) == DialogResult.cs using System.No) ev.EventArgs ev) { MessageBox. tb.Add(tb). b.Add(b).

} public static void Main() { Application. Image bgimage = new Bitmap("forest. System.7. gif or jpeg.ShowDialog().Run(new Fonts()). // mydrawim.Paint += new PaintEventHandler(Text_bru). tb. System.PaintEventArgs e) { Graphics g = e. System. } public void Text_bru(object sender.4.Drawing.cs using using using using System.Font.Drawing.1000. } public static void Main(string[] args) { Application.20.Drawing2D.EventArgs e) { flg. The file formats could be bmp. DISPLAYING IMAGES } public void b_click(object sender. } } 93 7.600).Windows. public class Texturedbru : Form { public Texturedbru() { this.bmp").Forms.Text = "Using Texture Brushes".Graphics. .Run(new Texturedbru()).20. g. this.DrawImage(bgimage.4 Displaying Images Next we provide a program that displays images using the method DrawImage.Font = flg.

bmp").Drawing.500.Paint += new PaintEventHandler(Text_bru).94 } } Another option to display the picture is // textbru.350.300).Text = "Using Texture Brushes".Forms.300). } } 7.Run(new Texturedbru()).130). bgbrush = new TextureBrush(bgimage).450. We create a Button and clicking on it switches the color of the circle from red to blue and vice versa. g.150.FillEllipse(bgbrush.Drawing2D.FillRectangle(bgbrush.cs using using using using System. public Texturedbru() { this.50.100.PaintEventArgs e ) { Graphics g = e. this. g. // MyOnPaint. Image bgimage = new Bitmap("forest. System.50.cs . } public static void Main() { Application.5 Overriding OnPaint The next program shows how to override OnPaint().150. System. GRAPHICS public class Texturedbru : Form { Brush bgbrush.FillEllipse(bgbrush. g.Graphics.450. System.Drawing. CHAPTER 7.Windows. } public void Text_bru(object sender.

} } 95 .5.Blue.Run(new Draw()).Text = "Click Me".Location = new Point(210. } e. } // end OnPaint void HandleClick(object sender.Blue) { b.Color = Color. using System.Color = Color.Drawing. } else { b. OVERRIDING ONPAINT using System.EventArgs e) { this. int y = 30.x. } public static void Main() { Application. if(b.diameter).220). } protected override void OnPaint(PaintEventArgs e) { int diameter = 200.FillEllipse(b.Red. button1. class Draw : Form { private SolidBrush b = new SolidBrush(Color. using System.Color == Color. button1. Controls. int x = 50.Graphics.diameter.Click += new EventHandler(HandleClick).Red). public Draw() { Button button1 = new Button(). button1.Refresh().Add(button1).Windows.y.Forms.7.

System.Black.x2. Pen myPen = new Pen(Color.EventArgs myEventArgs) { Invalidate(). System. g.MatrixOrder. System.y2). g. float y1 = ClientSize. } public TimerVector() { rot = 0. g. float x2 = (ClientSize. GraphicsState gs = g.TranslateTransform(-centerx. g. float y2 = (ClientSize.Width/2.Width/4.3).centery.Drawing.RotateTransform(rot.x1.TranslateTransform(centerx.Run(new TimerVector()).Height/4.AntiAlias.96 Another example we consider a rotation line.y1. .Save().Drawing.MatrixOrder.Height*3)/4. } protected override void OnPaint(PaintEventArgs pea) { Graphics g = pea. // Rotate. rot = (rot + 1)%360.SmoothingMode = SmoothingMode.Drawing2D.Graphics. g. float centery = ClientSize.Restore(gs).DrawLine(myPen.0f. CHAPTER 7. } private void TimerEvent(Object myObject.cs using using using using System.Forms. public static void Main() { Application.-centery).Append). g.Append). float centerx = ClientSize.Windows. float x1 = ClientSize. GRAPHICS class TimerVector : Form { float rot.Width*3)/4.Height/2.

using System. OVERRIDING ONPAINT Timer t = new Timer().500).ToString(). } set 97 .Forms. } } Another example is // Flicker.true).Now.playerPosition.UserPaint. } private Point PlayerPosition { get { return this.0).50).Enabled = true. class Flicker : Form { private Timer t = new Timer(). using System.Tick += new EventHandler(TimerOnTick).Drawing. t.5.Interval = 40. } private void TimerOnTick(object sender. t. this. public Flicker() { ClientSize = new Size(500. SetStyle(ControlStyles.Start().cs using System. t.Interval = 100.true). private Size playerSize = new Size(50. t. t.Refresh().ToString().Tick += new EventHandler(TimerEvent).true). t.KeyDown += new KeyEventHandler(OnKeyPress). SetStyle(ControlStyles.DoubleBuffer.Text = DateTime.Windows. SetStyle(ControlStyles.7.Text += " " + this.PlayerPosition. this.AllPaintingInWmPaint. this. private Point playerPosition = new Point(0.EventArgs e) { this.

this.Width).PlayerPosition.ClientSize.Width.X.Y = 0.PlayerPosition.playerSize.X-this. } if(e.KeyValue == 38) { this.playerSize.playerPosition.Y < 0) { this.PlayerPosition.Height.KeyValue == 39) { this.Y-this.Height.X = value.playerPosition.Width) { this.Height > this. } else { this.playerPosition.X+this.this.ClientSize.PlayerPosition.playerPosition.Y.Height) { this.playerPosition.Y).PlayerPosition = new Point(this.PlayerPosition = new Point(this.X.this.Y = value.Y+this.playerSize. } else if(value.PlayerPosition.Width-this.Y).Width > this.98 CHAPTER 7.playerSize.X+this. GRAPHICS { if(value.KeyValue == 37) { this.X = this.ClientSize.PlayerPosition = new Point(this.Width.Y = this. } else { this.Height-this.playerSize.playerSize.X < 0) { this.KeyEventArgs e) { if(e.PlayerPosition. } else if(value. } if(value.playerPosition.playerSize. . } if(e.X = 0. } } } private void OnKeyPress(object sender.ClientSize.

7.5. OVERRIDING ONPAINT }

99

if(e.KeyValue == 40) { this.PlayerPosition = new Point(this.PlayerPosition.X,this.PlayerPosition.Y+this.playerSize.Height); } } protected override void OnPaint(PaintEventArgs e) { e.Graphics.FillRectangle(new SolidBrush(Color.Red),this.PlayerPosition.X, this.playerPosition.Y,this.playerSize.Width, this.playerSize.Height); } public static void Main() { Application.Run(new Flicker()); } }

Chapter 8 Events
Event handling is familiar to any developer who has programmed graphical user interfaces (GUI). When a user interacts with a GUI control (e.g., clicking a button on a form), one or more methods are executed in response to the above event. Events can also be generated without user interactions. Event handlers are methods in an object that are executed in response to some events occuring in the application. To understand the event handling model of the .NET framework, we need to unterstand the concept of delegate. A delegate in C# allows us to pass methods of one class to objects to other classes that can call those methods. We can pass method m in class A, wrapped in a delegate, to class B and class B will be able to call method m. We can pass both static and instance methods. An event handler in C# is a delegate with a special signature, given below public delegate void MyEventHandler(object sender,MyEventArgs e) The first parameter (sender) in the above declaration specifies the object that fired the event. The second parameter (e) holds data that can be used in the event handler. The class MyEventArgs is derived from the class EventArgs. EventArgs is the base class of more specialized classes, like MouseEventArgs, ListChangedEventArgs, etc. Thus an event is a notification sent by a sender object to a listener object. The listener registers an event handler method with the sender. When the event occurs the sender invokes event handler methods of all its registered listerners. The event handler is registered by adding +=. The -= operator removes the handler from the event. As an example we set up two classes A and B to see how this event handling mechanism works in .NET framework. The delegates require that we define methods with the exact same signature as that of the delegate declaration. Class A will provide event handlers (methods with the same signature as that of the event declaration). It will create the delegate objects and hook up the event handler. Class A will then pass the delegate objects to class B. When an event occurs in class B, it will execute the event handler method of class B. 100

101 // MyHandler.cs using System; // Step 1. Create delegate object public delegate void MyHandler1(object sender,MyEventArgs e); public delegate void MyHandler2(object sender,MyEventArgs e); // Step 2. Create event handler methods class A { public const string m_id = "Class A"; public void OnHandler1(object sender,MyEventArgs e) { Console.WriteLine("I am in OnHandler1 and MyEventArgs is {0}",e.m_id); } public void OnHandler2(object sender,MyEventArgs e) { Console.WriteLine("I am in OnHandler2 and MyEventArgs is {0}",e.m_id); } // Step 3. Create delegates, plug in the handler and register // with the object that will fire the events public A(B b) { MyHandler1 d1 = new MyHandler1(OnHandler1); MyHandler2 d2 = new MyHandler2(OnHandler2); b.Event1 += d1; b.Event2 += d2; } } // end class A // Step 4. Call the encapsulated method through the delegate (fires events) class B { public event MyHandler1 Event1; public event MyHandler2 Event2; public void FireEvent1(MyEventArgs e) { if(Event1 != null) { Event1(this,e); } } public void FireEvent2(MyEventArgs e) { if(Event2 != null) { Event2(this,e); }

Location = new Point(40.40). } // end Main } CHAPTER 8. // evthand.Forms.Click += new EventHandler(HandleClick1).Add(button1).Drawing. button2. } // end class MyEventArgs class Driver { public static void Main() { B b = new B(). EVENTS The next program shows GUI event handling in C#.40). button2.Windows. b. Controls.102 } } // end class B public class MyEventArgs { public string m_id.FireEvent1(e1). using System.FireEvent2(e2). . A a = new A(b).Size = new Size(60.m_id = "Event args for event 2". button1. e1.m_id = "Event args for event 1". MyEventArgs e2 = new MyEventArgs().cs using System. b.Text = "Button". button1. using System. MyEventArgs e1 = new MyEventArgs(). e2. class MyForm : Form { MyForm() { // button1 top left corner Button button1 = new Button(). Button button2 = new Button(). We create two buttons each of them fires an event.

WriteLine("Console click fire!").Show("The click event fire!").Run(new MyForm()). } void HandleClick2(object sender. } } .Click += new EventHandler(HandleClick2). } public static void Main() { Application. Controls.Add(button2).Text = "New Button".EventArgs e) { MessageBox. } void HandleClick1(object sender.103 button2. button2.EventArgs e) { Console.

exe and asynchronously counts up from 0 to 100001. winhlp32. Thus we can start other applications from within our application. then destroys the notepad.exe"). string name = p.Chapter 9 Processes and Threads 9. The Process.1 Processes A process in its simplest form is a running application.Start("notepad. Console. 104 . It counts again from 0 to 2000 and then kills the winhlp32. DateTime started = p. Each process has an Id number.cs using System. The Process class provides access to local and remote processes and enables us to start and stop local system processes.WriteLine("id = " + id).exe process using the Kill() method.exe process. using System.exe.WriteLine("name = " + name). Console.Id. int id = p.Diagnostics.ProcessName.Start() method starts a process resource by specifying the name of a document or application file and associates the resource with a new process component.WriteLine("StartTime = " + started). The program below launches notepad.StartTime. class Processtest { public static void Main() { Process p = Process. // process1. Console.

p. and starts it.j<2000.Start("winhlp32. w.cs) with notepad. local variables.Threading.cs"). Thread thread = new Thread(job).Threading namespace provides various classes for executing and controlling threads. public class Threads0 { static void Main() { ThreadStart job = new ThreadStart(ThreadJob). Threads are part of the same process which execute concurrently. The detect process completion we use the method WaitForExit() 9.i<100001.Kill().1 Threads Introduction A thread is an execution stream within a process. and program counter. In . We create a Thread instance by passing it an object of ThreadStart delegate which contains a reference to our ThreadJob method. using System. . It has it own execution stack.j++) Console. } } 105 If we also want to load a file (for example process2. // Threads0.2. A thread is also called a lightweight process.i++) Console.WriteLine(j). for(int j=0. Thus the code creates a new thread which runs the ThreadJob method."c:\\csharp\\process2.Start("notepad.NET Base Class Library (BCL) the System. That thread counts from 0 to 1 while the main thread counts from 0 to 5.2.Kill(). There may be more than one thread in a process.cs is the simple example.2 9.9.exe". THREADS Process w = Process.exe"). for(int i=0.exe we change this line to Process p = Process.WriteLine(i).cs using System. The following program Threads0.

i++.WriteLine("Other thread: {0}". while(i < 2) { Console. while(i < 6) { Console.i).i). } // end while } // end Main static void ThreadJob() { int i = 0.WriteLine("Main thread: {0}". i++.cs the Thread t is set to the background thread . CHAPTER 9.2. } // end while } // end ThreadJob } An output could be Main thread: Main thread: Main thread: Main thread: Main thread: Main thread: Other thread: Other thread: 0 1 2 3 4 5 0 1 At another run the output could be Other thread: Other thread: Main thread: Main thread: Main thread: Main thread: Main thread: Main thread: 0 1 0 1 2 3 4 5 9.106 thread. PROCESSES AND THREADS int i = 0.Start().2 Background Thread In the program threadtest2.

i++) { Console.i).2.Suspend on another thread.. the call blocks until the thread is resumed by another thread. The Sleep method takes as a parameter a timeout.i<1001.WriteLine("Hello {0}". t.2. Calling Thread. which is the number of milliseconds that the thread should remain blocked. The thread will terminate when the application terminates. for(int i=1.i++) { Console.Suspend. Calling Thread.IsBackgound = true.i).Sleep(0) causes a thread to yield the remainder of its timeslice to another thread.Interrupt. THREADS t.Threading. A thread can also be paused by calling Thread. When one thread calls Thread.Start(). t. One thread cannot call Sleep on another thread. Calling Thread. } } } 107 9. The Sleep method is called when a thread wants to put itself to sleep. When a thread calls Thread.Suspend on itself. using System.IsBackground = true.cs using System. // threadtest2.Infinite) causes a thread to sleep until it is interrupted by another thread that calls Thread.3 Sleep Method Once a thread has been started it is often useful for that thread to pause for a fixed period of time.WriteLine("Bye {0}".Sleep causes the thread to immediately block for a fixed number of milliseconds. the call is a non-blocking call that causes the . } } public static void Main() { Thread t = new Thread(new ThreadStart(SayHello)).9. // for Thread class class ThreadTest2 { public static void SayHello() { for(int i=1.Sleep(Timeout.

108 other thread to pause.Start(). The way they count at different speeds is by each of them including a call to Thread. using System.i). Thread thread = new Thread(job).cs using System.i). } // end while } // end ThreadJob } . public class ThreadsSleep { static void Main() { ThreadStart job = new ThreadStart(ThreadJob). and starts it. thread.cs is the simple example. Thread. and between each count in the other thread we sleep for 500ms. We create a Thread instance by passing it an object of ThreadStart delegate which contains a reference to our ThreadJob method. Thread. CHAPTER 9.WriteLine("Other thread: {0}". i++. } // end while } // end Main static void ThreadJob() { int i = 0. int i = 0.WriteLine("Main thread: {0}".Sleep(). PROCESSES AND THREADS The following program Threads0. That thread counts from 0 to 9 fairly fast (about twice a second) while the main thread counts from 0 to 4 fairly slowly (about once a second). while(i < 10) { Console. i++. Thus the code creates a new thread which runs the ThreadJob method.Sleep(1000). Between each count in the main thread we sleep for 1000ms. while(i < 5) { Console. which just makes the current thread sleep (do nothing) for the specified period of time (milliseconds).Sleep(500). // ThreadsSleep.Threading.

i<6.i<3.WriteLine("Hello {0}".WriteLine("Welcome {0}". t.i). THREADS A typical output could be Main thread: Other thread: Other thread: Main thread: Other thread: Other thread: Other thread: Main thread: Other thread: Main thread: Other thread: Other thread: Main thread: Other thread: Other thread: 0 0 1 1 2 3 4 2 5 3 6 7 4 8 9 109 At another run this could change.9.cs using System.Join(). // joiningthread.i++) Console. using System.Threading.4 Join Methods The method Join() blocks the calling thread until a thread terminates. class JoiningThread { public static void Run() { for(int i=1.2.i).2.Start().WriteLine("Goodbye").i++) Console. 9. t. Console. } public static void Main() { Thread t = new Thread(new ThreadStart(Run)). for(int i=1. } .

Exit(obj). // waitingthread. PROCESSES AND THREADS 9.3 Monitor While one thread is in a read/increment/write operation. in which case when the current owner thread releases it for the last time.WriteLine("Welcome: {0}".i<6. public static void thread1() { for(int i=1. If a thread tries to acquire a monitor which is owened by another thread. Monitor. The Pulse(object) method notifies a thread in the waiting queue of a change in the locked object’s state. The monitor is only available to other threads again once it has exited as many times as it was entered.i). There may be more than one thread trying to acquire the monitor. no other threads can try to do the same thing. class WaitingThread { static object obj = new object().110 } The output is Welcome Welcome Welcome Welcome Welcome Hello 1 Hello 2 1 2 3 4 5 CHAPTER 9. or exit (or release) it. A thread can enter (or acquire) a monitor only if no other thread has currently “got” it.Pulse(obj). it can acquire it more times. Monitor. it will block until it is able to acquire it. Monitor.cs using System.the other one will have to wait for the new owner to release it too.NET has a monitor associated with it.Threading. Once a thread has acquired a monitor.Enter(obj). only one of the threads will acquire it . The method Wait(object) waits for the Monitor Pulse. This is where monitors come in. } . using System. Every object in .i++) Console.

Pulse(obj). The first program is without the lock operation.4 Synchronization When two or more threads share a common resource access needs to be serialized in a process called synchronization. Monitor. Thread t1 = new Thread(job1).Wait(obj).i++) Console. } public static void Main() { ThreadStart job1 = new ThreadStart(thread1).Start().i++) Console. } public static void thread3() { for(int i=1. In the second program the lock operation is introduced. ThreadStart job2 = new ThreadStart(thread2).Enter(obj). Synchronization is done with the lock() operation.Enter(obj). t3. ThreadStart job3 = new ThreadStart(thread3).i).WriteLine("Hello: {0}". .Exit(obj). Monitor. Monitor.WriteLine("Good Night: {0}".Start().i<8.9.4.i<15. Thread t2 = new Thread(job2). } } If thread3 runs last after thread1 and thread2 have completed it freeze at Good Night: 7 9. Monitor. SYNCHRONIZATION 111 public static void thread2() { for(int i=1. Monitor.Pulse(obj). Thread t3 = new Thread(job3). t1.Start(). Monitor.i). t2.Exit(obj). Monitor.

} } Now we introduce the lock.112 // syncthreads1. public static void Run() { acc.Sleep(10). using System. public void Withdraw(double amount) { Console.Threading.cs using System. // do other stuff balance -= amount. class Account { private double balance = 5000.Start(). if(amount > balance) throw new Exception("INSUFFICIENT FUNDS").WriteLine("BALANCE {0}". PROCESSES AND THREADS class Account { private double balance = 5000. acc. } public static void Main() { new Thread(new ThreadStart(Run)).Withdraw(3000). // syncthreads2. using System. Thread.Withdraw(3000). } } class SymnThread { static Account acc = new Account().WriteLine("WITHDRAWING {0}".balance).cs using System. .Threading. CHAPTER 9.amount). Console.

waiting for the monitor that it’s waiting for to be released .5. Each blocks. An example is given below. } Console. using System. } } class SymnThread { static Account acc = new Account().amount). public class Deadlock { .Sleep(10). lock(this) { if(amount > balance) throw new Exception("INSUFFICIENT FUNDS"). Thread. // Deadlock. public static void Run() { acc. DEADLOCK 113 public void Withdraw(double amount) { Console. } public static void Main() { new Thread(new ThreadStart(Run)).Withdraw(3000).WriteLine("BALANCE {0}". acc.9. this is when two threads each holds a monitor that the other one wants. Simply put.cs using System.and so the monitors are never released.5 Deadlock The second major problem of multi-threading is that of deadlocks. } } 9.WriteLine("WITHDRAWING {0}".Withdraw(3000).Threading. // do other stuff balance -= amount.balance). and the application hangs (or at least those threads involved in the deadlock hang).Start().

Console.Sleep(500). } // end method ThreadJob public static void Main() { new Thread(new ThreadStart(ThreadJob)). // Wait until we are fairly sure the first thread // has grabbed secondlock Thread. lock(secondLock) { Console. Console.WriteLine("Locked secondLock"). } Console.WriteLine("\t\t\t\tReleased secondLock"). } Console.WriteLine("\t\t\t\tLocking secondLock"). lock(firstLock) { Console.Sleep(1000). } Console.WriteLine("Released firstLock").Start(). static readonly object secondLock = new object(). static void ThreadJob() { Console. // wait until we are fairly sure the other thread // has grabbed firstlock Thread.WriteLine("Released secondLock").114 CHAPTER 9.WriteLine("\t\t\t\tLocking firstLock").WriteLine("\t\t\t\tLocked firstLock"). } Console.WriteLine("Locked firstLock"). PROCESSES AND THREADS static readonly object firstLock = new object().WriteLine("Locking secondLock"). Console. lock(firstLock) { Console.WriteLine("Locking firstLock").WriteLine("\t\t\t\tLocked secondLock").WriteLine("\t\t\t\tReleased firstLock"). } // end Main } // end class . lock(secondLock) { Console.

public class MyInterlocked { static long count = 0. using System. for(long i=0. for a long (64 bits) on a 32 bit machine. we cannot have another thread reading the value half way through the write. Console. INTERLOCKED CLASS 115 9. For example. we cannot have another thread changing the value half way through the read. } thread.i<5. . Sinilarly.in other words. The Interlocked class provides a set of methods for performing atomic changes: exchanges (optionally performing a comparison first).Start(). Thread thread = new Thread(job). Console. } // end Main static void ThreadJob() { long i = 0. or float.cs using System.Increment(ref count). increments and decrements. object. // interlocked. the Increment and Decrement methods act on variables of type int and long. ending up with a value which is neither the old nor the new value. Thus with an atomic write.i++) { Interlocked. and ending up “seeing” half of the old value and half of the new value.6 Interlocked Class An operation is atomic if it is indivisible .9. if one thread is changing the value from 0 to 0x0123456789ABCDEF. The Exchange and CompareExchange methods act on a variables of type int. with an atomic read.count). nothing else can happen in the middle.WriteLine("I am in for loop in main").Threading. thread.Join(). there is no guarantee that another thread will not see the value as 0x0123456700000000 or 0x0000000089ABCDEF. public static void Main() { ThreadStart job = new ThreadStart(ThreadJob).6.WriteLine("final count: {0}".

PROCESSES AND THREADS while(i < 5) { Interlocked. } } // end ThreadJob } First the for loop in Main will run to the end and then the while loop will be done. but often those threads spend a great deal of time in the sleeping state waiting for an event to occur. int[] a1 = (int[]) o. for(int i=0. for(int i=0. using System. Console.i<a2. } public static void Sum2(Object o) { int sum2 = 0. depending on our application.116 CHAPTER 9.WriteLine("I am in ThreadJob"). // ThreadsSum2. int[] a2 = (int[]) o. Using thread pooling provides our application with a pool of worker threads that are managed by the system. Other threads might enter a sleeping state and be awakend only periodically to poll for a change or update status information before going to sleep again.Length. } Console.i<a1.Threading. i++. Many applications use multiple threads.cs using System.7 Thread Pooling We can use thread pooling to make much more efficient use of multiple threads.WriteLine("sum1 = " + sum1). class ThreadsSum { public static void Sum1(Object o) { int sum1 = 0.Length.i++) . An example is given below.i++) { sum1 += a1[i].Increment(ref count). 9. allowing us to concentrate on application tasks rather than thread management.

BeginInvoke and EndInvoke methods have been provided so that we can ask the UI thread to call a method in a safe manner. etc.a2)) Console. 2) Never execute a long-running piece of code in the UI thread. and InvokeRequired. 4 }. THREADING IN WINDOWS FORMS { sum2 += a2[i].9. If our code is running in the UI thread. Thread.QueueUserWorkItem(new WaitCallback(Sum2).a1)) Console. Each control is effectively bound to a thread which runs its message pump. which are harder to diagnose and fix than ”normal” threading problems. 3. It means we have to consider re-entrancy issues etc. } public static void Main() { int[] a1 = { 2. Fortunately. BeginInvoke. 7 }. We can execute longrunning code and periodically call Application. that means no other code is running in that thread. our controls won’t be repainted.WriteLine("sum2 = " + sum2).8.Sleep(10). if(ThreadPool. we run a risk of our program hanging or misbehaving in other ways. There are message pumping issues in terms of COM objects as well. } Console. and make . if(ThreadPool. If we try to access or change anything in the UI (for example changing the Text property) from a different thread.8 Threading in Windows Forms How to handle threading in a UI? There are two rules for Windows Forms: 1) Never invoke any method or property on a control created on another thread other than Invoke.WriteLine("Sum2 queued").QueueUserWorkItem(new WaitCallback(Sum1). int[] a2 = { 4. 5. // Give other threads a turn } } 117 9. If we have a piece of long-running code which we need to execute. That means we won’t receive events. EndInvoke or CreateGraphics. the Invoke. and we can’t use anything which might block (network access.WriteLine("Sum1 queued").DoEvents(). we need to create a new thread (or use a thread pool thread if we prefer) to execute it on. for instance) without risking an unresponsive UI. We may get away with it in some cases. We have to judge when to call DoEvents.

However. Button button. System. for example). Using state somewhere is necessary if we are creating a new thread rather than using the thread pool .Empty. The first option is to have state in the class itself. public class Test : Form { delegate void StringParameterDelegate(string value). If we use BeginInvoke.Windows.Forms. System. The thread creation part is the same as any other threading problem. PROCESSES AND THREADS sure it doesn’t directly try to update the UI with its results. retrieving and processing it in the other (updating the display in the UI thread. If we use Invoke. Label statusIndicator. The second option is to pass the information as parameters in the delegate. and is in some ways less efficient than using a simple MethodInvoker or EventHandler delegate. MethodInvoker is just a delegate which takes no parameters and returns no value (like ThreadStart). These two delegates are treated in a special (fast) manner by Invoke and BeginInvoke. If we need to get the return value of a delegate invoked asynchronously. There are two different ways of invoking a method on the UI thread. There are two options when working out how to get information between the various threads involved.when the method is invoked.cs using using using using System. // ThreadingForms.we specify a delegate and (optionally) some arguments. setting it in one thread. they are ignored .118 CHAPTER 9. Label counter. and EventHandler takes two parameters (a sender and an EventArgs parameter and returns no value.Drawing. System. the sender will be the control we have invoked it with. It is interesting going the other way . and the EventArgs will be EventArgs.but that doesn’t mean we have to use state to return information to the UI. we can use EndInvoke with the IAsyncResult returned by BeginInvoke to wait until the delegate has completed and fetch the return value. creating a delegate with lots of parameters feels clumsy.invoking a method on the UI thread in order to update the UI. Here is an example which shows several of the above concepts. and a message goes on the queue for the UI thread to process. However if we pass an EventHandler delegate to Invoke or BeginInvoke then even if we specify parameters ourself. one synchronous (Invoke) and one asynchronous (BeginInvoke). the call will return immediately.Threading. . the current thread will block until the delegate has been executed. They work in much the same way . readonly object stateLock = new object().

Location = new Point(10. counter.10). statusIndicator.Click += new EventHandler(StartThread).Add(button). Test() { Size = new Size(180.Size = new Size(50. button. Controls. Random rng = new Random(). button = new Button(). Controls. button.Text = "Count:". lock(stateLock) { 119 .Size = new Size(100.58). } void StartThread(object sender. lbl.Add(statusIndicator).20). lbl. int currentCount.34).Location = new Point(70.Text = "Run".34).20). statusIndicator = new Label(). THREADING IN WINDOWS FORMS int target. counter. Text = "Test".Enabled = false.20). lbl.Size = new Size(100.Add(lbl).Text = "Status:".Location = new Point(70. lbl. Controls.20).Location = new Point(10. statusIndicator.Add(lbl). button.9. lbl = new Label().Add(counter). lbl.Location = new Point(10. Label lbl = new Label().EventArgs e) { button. lbl.Size = new Size(50. button.Size = new Size(50.120).8. Controls. counter = new Label().20).10). Controls.

for(int i=0. t. int localTarget. } Thread t = new Thread(new ThreadStart(ThreadJob)).IsBackground = true. } void UpdateStatus(string value) { if(InvokeRequired) { // We’re not in the UI thread. } UpdateStatus("Starting").Sleep(500).120 CHAPTER 9. } Invoke(updateCounterDelegate). Invoke(new MethodInvoker(EnableButton)). } void ThreadJob() { MethodInvoker updateCounterDelegate = new MethodInvoker(UpdateCount). lock(stateLock) { currentCount = 0. PROCESSES AND THREADS target = rng.i++) { lock(stateLock) { currentCount = i. . // Pause before starting Thread. } UpdateStatus("Finished"). Thread.i<localTarget.Start().Sleep(100). lock(stateLock) { localTarget = target. UpdateStatus("Counting"). so we need to call BeginInvoke BeginInvoke(new StringParameterDelegate(UpdateStatus). t. } // Synchronously show the counter Invoke(updateCounterDelegate).Next(100).new object[]{value}).

If it does. BeginInvoke . which uses InvokeRequired to detect whether or not it needs to ”change thread”. but slightly harder work in that we would either have to have another method anyway. The choice of BeginInvoke rather than Invoke here was just to demonstrate how to invoke a method asynchronously.9. } // Must be on the UI thread if we’ve got this far statusIndicator.Run(new Test()). } } 121 State is used to tell the worker thread what number to count up to. Unlike all other asynchronous methods we do not need to call EndInvoke unless we need the return value of the delegate’s method. A delegate taking a parameter is used to ask the UI to update the status label. In this case we actually know that BeginInvoke is required because we are running in the worker thread anyway. or get the MethodInfo for the property setter in order to construct the delegate to invoke. THREADING IN WINDOWS FORMS return. In real code. This is quite a common way of making a method which interacts with the UI thread-safe. The worker thread’s principal method actually just calls UpdateStatus. It is easier to use from the client code. so we should use BeginInvoke instead of Invoke.Text = value. } void UpdateCount() { int tmpCount. Another approach might be to have a property which did the appropriate invoking when necessary.Text = tmpCount. } counter.ToString(). lock(stateLock) { tmpCount = currentCount. we would decide based on whether we needed to block to wait for the access to the UI to complete before continuing or not.8. We do not call EndInvoke after the BeginInvoke.Enabled = true. } static void Main() { Application. It is quite rare to actually require UI access to complete first. } void EnableButton() { button. it then calls BeginInvoke to execute the same method again from the UI thread.

} . If we call BeginInvoke it will have a different effect than calling the method directly as it will occur later.System. This time there’s no attempt to detect whether or not an Invoke is required. BeginInvoke and EndInvoke methods.int m.int m). The compiler will emit the MyWorker class class MyWorker : System. and another MethodInvoker delegate is used to enable the button again afterwards. Again. and we end up with deadlock.IAsyncResult result).AsyncCallback cb. In other cases where we have a thread which should keep running even after the UI thread has quit. public System. 9. .we will either block permanently (waiting for the message to be taken off the queue.9 Asynchronous Programming Model When a caller invokes a method. State is used again to tell the UI thread how far we have counted so far. For every delegate declared in an assembly the compiler emits a class (subclass of System. public int EndInvoke(System.) so that when the UI thread exits. We use a MethodInvoker delegate to execute UpdateCount. It is disabled while the thread is running. PROCESSES AND THREADS is also different to all of the other asynchronous methods as it doesn’t cause the delegate to be run on a thread pool thread. the whole application finishes.MulticastDelegate) with Invoke.MulticastDelegate { public int Invoke(char c. we actually know that we need to call Invoke here anyway. For example. of course.122 CHAPTER 9. not updating the UI or anything else while holding the lock. A button is provided to let the user start the thread. We spend as little time as possible in the lock. The worker thread is set to be a background thread (IsBackground=true. All state which is shared between threads (the current count and the target) is accessed in locks in the way described earlier. rather than in the current execution flow.NET has an inbuilt support for asynchronous method invocation. This probably doesn’t make too much difference here. object asyncState).int m).the UI thread would then try to acquire the lock as well. we need to be careful not to call Invoke or BeginInvoke when the UI thread is no longer running . Here the caller can issue a request for invocation of a method and concurreently execute the remaining code. with nothing actually looking at messages) or receive an exception. the call is synchronous that is the caller has to wait for the method to return before the remaining code can be executed. consider a delegate declared as delegate int MyWorker(char c. We call this using Invoke to make sure that it executes on the UI thread. It would be disastrous to still have the lock in the worker thread when synchronously invoking UpdateCount .IAsyncResult BeginInvoke(char c.

// Asynchronous.cs using System.int m). TIMERS 123 The BeginInvoke and EndInvoke methods can be used for asynchronous invocation of a method pointed by MyWorker delegate.1000). return (Environment.Read() to pause the main thread.TickCount . All the timers implement IDispossible. // returns number of milliseconds // elapsed since the system started for(int i=1. in the next statement this method is directly invoked with character ’*’.t). worker = new MyWorker(DoWork). // pause until user presses a key } } 9. each of which basically calls a delegate after a certain amount of time has passed.Write(c).int m) { int t = Environment.9. worker. static int DoWork(char c.NET.10 Timers There are various different timers available in .10. Both ’+’ and ’*’ are displayed (1000 times each) on the Console simultaneously.Read().i<=m.i++) Console.cs .1000. In the program below the method DoWork (it displays character c m number of times) is invoked asynchronously with character ’+’.null. delegate int MyWorker(char c. // synchronous call Console.BeginInvoke(’+’. As an asynchronous call executes within its own background thread. class AsncTest { static MyWorker worker. so we have to make sure to dispose when we are not using them anymore. we have used Console.TickCount. // asynchronous call DoWork(’*’. // Timers.WriteLine("Start").null). } public static void Main() { Console.

11 Interrupt and Abort There are two methods in the Thread class which are used for stopping threads Abort and Interrupt.Now).WriteLine("Ticked at {0:HH:mm:ss. or immediately if the thread is already in that state.Threading.Threading. } } 9.Sleep(10000). This causes a ThreadInterruptedException exception to be thrown the next time the thread enters the WaitSleepJoin state.Interrupt is similar.cs using System.2000). } // the timerm will now have been disposed automatically due // to the using statement so there won’t be any other threads running } // end Main() static void Tick(object state) { Console. // Interruptthread.fff}".Abort aborts that thread as soon as possible. Calling Thread.124 using System. // then go slow for another 10 seconds timer.1000)) { // wait for 10 seconds Thread. Calling Thread.WriteLine("Started at {0:HH:mm:ss. CHAPTER 9.DateTime. but less drastic.3000. // Start in three seconds. Aborting a thread which is executing unmanaged code has no effect until the CLR gets control again.null. class SleepingThread { public static void Run() . PROCESSES AND THREADS public class Timers { public static void Main() { Console.DateTime.fff}".Sleep(10000). using System.Now).Change(0. Thread. using System. then fire every second using(Timer timer = new Timer(new TimerCallback(Tick).

WriteLine("Hello {0}". t.i<6..i++) Console.i++) { Console.WriteLine("Goodbye").WriteLine("Hello {0}".Threading.i<16. // threadtest1. } catch(ThreadInterruptedException e) { Console. 125 .WriteLine("Sleep Interrupted"). } } The program threadtest1.i). // for Thread class class ThreadTest1 { public static void SayHello() { for(int i=1.Interrupt(). using System.Start().11. } } public static void Main() { Thread t = new Thread(new ThreadStart(SayHello)).cs uses the Abort method.9.i++) Console. } public static void Main() { Thread t = new Thread(new ThreadStart(Run)). } Console. for(int i=1.cs using System. try { Thread.i).i). t. INTERRUPT AND ABORT { for(int i=1.Sleep(5000).WriteLine("Welcome {0}".

i++) { Console.i<1001. } t. for(int i=1.Start().WriteLine("Bye {0}". PROCESSES AND THREADS t. } } .126 CHAPTER 9.Abort().i).

This call typically blocks until a client connects with the server. Accept a connection. but the server does not need to know the address of (or even the existence of) the client prior to the connection being established. For the server socket on the Internet. Send and receive data The steps for establishing a socket on the server side are: 1. The system calls for establishing a connection are different for the client and the server. 4. The steps for establishing a socket on the client side are: 1. 3. the client. the server. typically to make a request for information. 127 . Connect the socket to the address of the server 3. Listen for connections.Chapter 10 Sockets Programming 10. The client needs to know of the existence of and the address of the server. an address consists of a port number on the host machine. The two processes each establish their own socket. One of the processes. A good analogy is a person who makes a phone call to another person. Once a connection is established. but both involve the basic construct of a socket. both sides can send and receive information. Create a socket 2. Create a socket 2. A socket is one end of an interprocess communication channel. Bind the socket to an address.1 Introduction Most interprocess communication uses the client server model. connects to the other process. These terms refer to the two processes which will communicating with each other.

When the server program is run it will indicate at which IPAddress it is running and the port it is listening to. The server on reciept of the string will display it.2 Transmission Control Protocol TCP is reliable connection oriented protocol. The client will ask for the string which is to be transmitted to the server. A socket is normally identified by an integer which may be called the socket descriptor.128 5. When the connection is established the server will display the IPAddress and port from where it has accepted the connection. . SOCKETS PROGRAMMING Thus a socket is a communication mechanism. CHAPTER 10. Send and receive data.2 BSD Unix system in 1983 in conjunction with the TCP/IP protocols that first appeared in the 4. Example 1. Now run the client program so that we establish a connection with the server. The socket mechanism was first introduced in the 4. send an acknowledgement which will be received by the client.1 BSD Unix system in late 1981. There are 1) 2) 3) 4) The The The The remote host identification number or address (IPAddress) remote host port number local host identification number or address (IPAddress) local host port number 10. Formally a socket is defined by a group of four numbers. Thus besides the IPAddress we also need a port number (2 bytes) which is arbitrary except for the well know port numbers associated with popular applications.

Console.LocalEndpoint). Console.40.. // start listening at the specified port 2055 listener. System. } // end catch } // end Main } // end class Server1 . Console. 129 class Server1 { public static void Main() { try { // use local IP address and use the same in the client IPAddress ipAd = IPAddress. Socket s = listener. TRANSMISSION CONTROL PROTOCOL // Server1. listener. ASCIIEncoding asen = new ASCIIEncoding().. for(int i=0.Sockets.WriteLine("Server is running at port 2055.").WriteLine("Waiting for a connection.StackTrace). System.i++) Console.Start().").RemoteEndPoint).GetBytes("The string was received by the server.WriteLine("\nSent Acknowledgement").ToChar(b[i]))..10. Console.Write(Convert. Console.cs using using using using System.Stop()."). TcpListener listener = new TcpListener(ipAd.. int k = s.106.")).Send(asen. " + e..Net. byte[] b = new byte[100].WriteLine("Connection accepted from " + s.Parse("152..Net. System..AcceptSocket(). s.WriteLine("Received.Text.2055).2.i<k.WriteLine("Error.Receive(b).84").WriteLine("The local End point is: " + listener. } // end try catch(Exception e) { Console. // clean up s. Console..Close().

byte[] ba = asen. Console.Write(ba.i<k.Read(bb. String str = Console.0. tcpclnt. Console. System.130 // Client1.StackTrace). " + e.GetBytes(str).40.cs using using using using using System.Length). stm. byte[] bb = new byte[100].100).Write("Enter the string to be transmitted: ").2055).i++) Console...Write(Convert.Connect("152. System.. // clean up tcpclnt. } // end catch } // end Main } // end class Client1 .").106.Sockets.ba.WriteLine("Error.ToChar(bb[i])).Text. int k = stm. for(int i=0.WriteLine("Connecting. Console. SOCKETS PROGRAMMING class Client1 { public static void Main() { try { TcpClient tcpclnt = new TcpClient().").84". System.IO..ReadLine().Net.WriteLine("Transmitting.0. ASCIIEncoding asen = new ASCIIEncoding(). } // end try catch(Exception e) { Console.Net. Console. Stream stm = tcpclnt.Close().WriteLine("Connected"). System..GetStream(). CHAPTER 10..

System. In our second example we include an xml-file (Server2.Sockets.106. Next we compile the Client side csc Client2. #endif for(int i=0.cs The code between #if LOG and endif will be added by the compiler only if the symbol LOG is defined during compilation (conditional compilation). listener. } // end for loop } // end Main public static void Service() { while(true) . On the Server side we first compile csc /D:LOG Server2.2055).Configuration.84"). System. System. #if LOG Console.WriteLine("Server mounted.Net.Threading.exe.i++) { Thread t = new Thread(new ThreadStart(Service)). // Server2. class EmployeeTCPServer { static TcpListener listener.i<LIMIT. // 5 concurrent clients public static void Main() { IPAddress ipAd = IPAddress. t.Start(). System.config) on the Server side we can query from the Client. TRANSMISSION CONTROL PROTOCOL 131 Example 2.10.listening to port 2055").Start(). const int LIMIT = 5.cs Then on the Server side we start running the exe-file Server2 and finally we start the exe-file Client2 on the Client side.cs using using using using using using System.40.Parse("152.2.IO. listener = new TcpListener(ipAd.Net. System.

WriteLine(e. StreamReader sr = new StreamReader(s). sw.WriteLine("{0} Employees available".132 CHAPTER 10. while(true) { string name = sr. #endif try { Stream s = new NetworkStream(soc).ReadLine().ConfigurationManager.soc. #endif } // end catch #if LOG Console. string job = ConfigurationManager.RemoteEndPoint). sw.Close(). if(name == "" || name == null) break.Close().RemoteEndPoint).AcceptSocket().AppSettings.Count). } // end while s. // enable automatic flushing sw.Message). } // end try catch(Exception e) { #if LOG Console. } } } // end class Server2 .WriteLine("Disconnected: {0}".AutoFlush = true. if(job == null) job = "No such employee". SOCKETS PROGRAMMING { Socket soc = listener. #if LOG Console. #endif soc. StreamWriter sw = new StreamWriter(s).WriteLine(job).AppSettings[name].WriteLine("Connected: {0}".soc.

exe.10.config is given by <configuration> <appSettings> <add key="john" value="manager"/> <add key="jane" value="steno"/> <add key="jim" value="clerk"/> <add key="jack" value="salesman"/> </appSettings> </configuration> 133 . TRANSMISSION CONTROL PROTOCOL The file (xml-file) Server2.2.

} finally { // code in finally block is guranteed to execute irrespective // whether any exception occurs or does not occur in the try block client.ReadLine().106.ReadLine()).AutoFlush = true.Close(). StreamWriter sw = new StreamWriter(s).Net. sw. Console. string name = Console. StreamReader sr = new StreamReader(s). Console.Close().WriteLine(name).2055). while(true) { Console.134 The Client2. CHAPTER 10. sw. SOCKETS PROGRAMMING class Client2 { public static void Main() { TcpClient client = new TcpClient("152.WriteLine(sr.cs is given by // Client2.Sockets. using System.WriteLine(sr.cs using System.Write("Name: "). } // end finally } // end Main } // end class Client2 .GetStream(). } // end while s. using System. try { Stream s = client.40.84". if(name == "") break.IO.ReadLine()).

byte[] sdata = Encoding. USER DATAGRAM PROTOCOL 135 10. System. IPEndPoint ep = null.GetString(rdata).config is given by <configuration> <appSettings> <add key="john" value="manager"/> <add key="jane" value="steno"/> <add key="jim" value="clerk"/> <add key="jack" value="salesman"/> </appSettings> </configuration> . string job = ConfigurationManager.Receive(ref ep).exe. udpc.Sockets.AppSettings[name]. System. The UDPServer1.3 User Datagram Protocol UDP is not very reliable (but fast) connectionless protocol.Send(sdata. System.10. } // end while } // end Main } The xml-file UDPServer1.cs file is given by // UDPServer1.sdata.Net. System. Example.cs using using using using using System. Console. while(true) { byte[] rdata = udpc.ASCII.Net.3.Text.ASCII.Length. if(job==null) job = "No such employee".GetBytes(job). string name = Encoding.WriteLine("Server started servicing on port 2055").ep).Configuration. class ServerUDP { public static void Main() { UdpClient udpc = new UdpClient(2055).

106. byte[] sdata = Encoding.config) on the Server side we can query from the Client.2055).ReadLine().sdata.cs Then on the Server side we start running the exe-file UDPServer1 and finally we start the exe-file UDPClient1 on the Client side.WriteLine("job = " + job).Receive(ref ep).Send(sdata.cs Next we compile the Client side csc UDPClient1.40. string job = Encoding.cs using using using using System.Net.Text.ASCII.cs file is given by // UDPClient1. On the Server side we first compile csc UDPServer1. string name = Console. System.Sockets. . SOCKETS PROGRAMMING class ClientUDP { public static void Main() { UdpClient udpc = new UdpClient("152.ASCII.84". while(true) { Console. udpc. CHAPTER 10.Length). Console. System. System. if(name == "") break. } // end while } // end Main } We include an xml-file (UDPServer1.GetBytes(name).136 The UDPClient1. byte[] rdata = udpc.Net.Write("Name: ").exe. IPEndPoint ep = null.GetString(rdata).

RegisterChannel(c).WriteLine("Server ready. Console. IChannel c = new HttpChannel(8080). ChannelServices. To set up remoting we proceed as follows: Instantiate target object (on server) Setup our channels Register our object (on server) Get a reference to object (on client) Call method on server from the client For example on the Server side: public class Server { public static void Main() { Target t = new Target().1 Introduction Object running in one Virtual Machine (VM) should be able to access (call functions on) objects that are in a different Virtual Machine. } } 137 ."me"). RemotingServices. Console. Usually this means the two processes are running on two different computers.Chapter 11 Remoting 11.ReadLine().Marshal(t. ").

138 On the Client side we have public class Client { public static void Main() {

CHAPTER 11. REMOTING

string url = "http://localhost:8080/me"; Type to = typeof(Target); Target t = (Target) RemotingServices.Connect(to,url); Console.WriteLine("Connected to server."); try { string msg = Console.ReadLine(); t.sendMessage(msg); } catch(Exception e) { Console.WriteLine("Error " + e.Message); } } } A shared class (i.e. it is on the Client and Server side) is public class Target : System.MarshalByRefObject { public void sendMessage(string msg) { System.Console.WriteLine(msg); } } Reference types passed via remoting must be serializable or marshal-by-reference. Serializable == pass-by-value Copy of object is made. MarshalByRefObject == pass-by-reference proxy object is passed. An example for the second case is: public class Counter : MarshalByRefObject { int count = 0; public void incCount() { count++; } public int getCount() { return count; } } An example for the first case is:

11.1. INTRODUCTION [Serializable] public class Counter { int count = 0; public void incCount() { count++; } public int getCount() { return count; } } We have to import: using using using using using System; System.Runtime.Remoting; System.Runtime.Remoting.Channels; System.Runtime.Remoting.Channels.Http; // for Http System.Runtime.Remoting.Channels.Tcp; // for Tcp

139

Shared objects must be available to both the client and the server. Make a separate assembly for it csc /t:library Shared.cs csc /r:Shared.dll Server.cs csc /r:Shared.dll Client.cs There are three main items in the process of remoting. The Interface, the Client and the Server. The Interface is a .dll file (generated from a .cs file) which is on the Client and Server side. The Server provides an implementation of the Interface and makes it available to call. The Client calls the Server using the Interface.

140

CHAPTER 11. REMOTING

Example. The client provides a string to the server and the server returns the length of the string. We first create an interface with the file MyInterface.cs. // MyInterface.cs public interface MyInterface { int FunctionOne(string str); } MyInterface.cs is on the Server and Client side. We compile to MyInterface.dll on the Client and Server side with csc /t:library MyInterface.cs On the Server side we now create our class which we invoke from a remote machine (client). RemoteObject.cs is on the Server side and is the implementation of MyInterface.cs. // RemoteObject.cs using System; using System.Runtime.Remoting; using System.Runtime.Remoting.Channels; public class MyRemoteClass : MarshalByRefObject, MyInterface { public int FunctionOne(string str) { return str.Length; // length of string } } Any class derived from MarshalByRefObject allows remote clients to invoke its methods. Now on the Server side we compile csc /t:library /r:MyInterface.dll RemoteObject.cs This creates the file RemoteObject.dll on the Server side.

We use ChannelServices.WriteLine("Press ENTER to quit"). We use SingleCall mode here which means a new instance is created for each remote call.Runtime.ReadLine(). This could cause problems with firewalls. We are using the string FirstRemote here which will be used as part of the URL that the client uses to access the remote object. Remark.RegisterWellKnownServiceType to register our RemoteClass object as a well-known type. System. "FirstRemote".cs using using using using System.cs .1.RemoteObject"). We select 9999 as the TCP port to listen on.Runtime. System.GetType("MyRemoteClass.11. } // end Main } // end class MyServer First we create a TcpChannel object which we use to transport messages across our remoting boundary.Console.Channels.RegisterWellKnownServiceType( Type. ChannelServices. // ServerTcp.RegisterChannel(m_TcpChan.SingleCall).Tcp.RegisterChannel to register our TcpChannel with the channel services. System. RemotingConfiguration. Next we generate the exe file for ServerTcp via csc /r:RemoteObject. Now this object can be remoted.Remoting. System. One could have also used Singleton in which case one object would have been instantiated and used by all connecting clients.WellKnownObjectMode. INTRODUCTION Next we provide our Server on the Server side.dll ServerTcp. System. Then we use RemoteConfiguration.false).Remoting. 141 public class MyServer { public static void Main() { TcpChannel m_TcpChan = new TcpChannel(9999).Remoting.Channels.Console.Runtime.

Channels. ChannelServices.168.0.RegisterChannel(m_TcpChan.GetObject(typeof(MyInterface).FunctionOne("willi hans steeb")).3 with the port 9999. We use Activator.RegisterWellKnownServiceType on the Server. public class MyClient { public static void Main() { TcpChannel m_TcpChan = new TcpChannel().cs . The IP address of the remote machine (Server) is 192. // ClientTcp. System.false). "tcp://192. though in this case we do not have to specify a port.Runtime.cs using using using using System.dll ClientTcp. System.142 CHAPTER 11.Tcp.Runtime.cs on the client side. REMOTING Now we write our Client program ClientTcp.Runtime. } // end Main } // end class MyClient Just as in the Server we have a TcpChannel object.0.RegisterChannel to register the channel.168. // for LocalHost // "tcp://LocalHost:9999/FirstRemote").Remoting.GetObject to obtain an instance of the MyInterface object.exe file we run csc /r:MyInterface. MyInterface m_RemoteObject = (MyInterface) Activator.WriteLine(m_RemoteObject. We also use ChannelService.Remoting.3:9999/FirstRemote"). Console.Remoting.Channels. To obtain the ClientTcp. System. The string FirstRemote which forms part of the URL was that we passed to RemotingConfiguration.

INTRODUCTION To run everything on the Server side we enter the exe file at the command line ServerTcp Then on the Client side we enter the exe file at the command line ClientTcp Then we are provide with the length of the string.11. 143 .1. In the present case 16.

System.Http. REMOTING Instead of using Tcp we can also use Http. // ServerHttp.RegisterWellKnownServiceType( Type.SingleCall).RegisterChannel(chan.Runtime.144 CHAPTER 11. System.GetType("MyRemoteClass.WellKnownObjectMode.cs are replaced by ServerHttp. Then the files ServerTcp. } // end Main } // end class MyServer .WriteLine("Press ENTER to quit").Console.Runtime. "FirstRemote". RemotingConfiguration.cs and ClientTcp.cs // on Server side using using using using System.Remoting.Runtime.Console.Remoting.cs and ClientHttp. System. System. ChannelServices.Channels.Remoting.false). System.cs shown below. public class MyServer { public static void Main() { HttpChannel chan = new HttpChannel(8080).RemoteObject").Channels.ReadLine().

Remoting. System.42:8080/FirstRemote").Channels. ChannelServices.WriteLine(m_RemoteObject. } // end Main } // end class MyClient .false).Remoting.Runtime.1.11.FunctionOne("willi hans")). Console. 145 public class MyClient { public static void Main() { HttpChannel chan = new HttpChannel().Http. // for LocalHost // "tcp://LocalHost:9999/FirstRemote"). "http://152. System.Channels.Remoting.cs // on client side using using using using System. MyInterface m_RemoteObject = (MyInterface) Activator.RegisterChannel(chan. System.Runtime.GetObject(typeof(MyInterface). INTRODUCTION // Client.Runtime.106.41.

SQLClient is used for Microsoft’s SQL Server and OLEDB is used for all other database formats. using System. using System. ADO. A disconnected data access model is frugal with resources.1 Introduction The .NET Data Provider is set up. A Data Provider consists of • Connection • Command • DataReader • DataAdapter 146 .NET to access databases. In order to use OLEDB the following namespace must be specified.SqlClient. Accessing a database requires that a . It operates on a disconnected data access model.NET Framework. There are two basic types of connections.NET is a set of managed classes within the .NET Framework uses ADO.Chapter 12 Accessing Databases 12. In order to use SQL with SQL Server or SQL Server Express the following namespace must be specified. When an application requests data a new database connection is created and destroyed when the request is completed. ADO.Data. which is desirable.NET allows access to many different databases.Data.OleDb. One important advantage of ADO.NET is that information is stored and transferred in XML.

read-only database access. A Connection String is required to connect to a database. The easiest way to find the correct connection string for a DBMS is to search the Web.SqlClient. The Connection creates the actual connection to the database.12. A DataAdapter handles retrieving and updating data.2 Examples The following program shows how to connect to a Microsoft SQL Server 2005 or Sql Express database and retrieve some basic information about the server. A DataSet is not always required. using using using using System. For example. It can be manipulated and updated independantly of the database. A good site to start with is http://www.Data. The data is not cached. System. The Command executes an instruction against the database. Knowledge of SQL is required. It decouples the DataSet from the database and allows a single DataSet to represent more than one database. System.Text. In order to open and close a database connection the Connection methods Open and Close are used respectively. 12. this could be a SQL query or a stored procedure. System.User ID=JoeUser.Password=User1234".Data. It is a middle-layer between the database (Data Provider) and the disconnected DataSet.Initial Catalog=dbTest.com.connectionstrings. It returns individual rows directly to the application. A DataSet can contain a set of tables with all the metadata necessary to represent the structure of the original database. EXAMPLES 147 A Dataset can be understood as a virtual database table that resides in RAM. for example the userid and password. Care must be taken is creating an appropriate connection string (CON STRING in these examples). . A DataReader is used for fast and efficient forward-reading.2. The Connection object contains all the information needed to open the connection. namespace csDB { class OpenSQLDB { public const string CON_STRING = "Data Source=mySqlDB.

cmDB.pwd=User1234. SqlConnection connection = new SqlConnection(CON_STRING).WriteLine("Stats Enabled: {0}". In addition.user id=JoeUser. is not a good idea. string CON_STRING=ConfigurationSettings.ServerVersion). connection. . } // end Main } // end class } // end namespace Embedding the user ID and password. SqlDataReader myReader = cmDB.DataSource).config.ExecuteReader(). as in the above code.config file.WriteLine("Server Version: {0}". The basic method of retrieving data using a Data Reader is as follows..WriteLine("Data Source: {0}". connection. SqlCommand cmDB = new SqlCommand().StatisticsEnabled). Console.CommandText = "SELECT * FROM tblCustomer".newdb. connection. A standard SQL query is used and submitted to the database via a SqlCommand object. In the case of data retrieval the SELECT statement is used.net. cmDB..Connection = connection . Console. <\configuration> The following line of code fetches the connection string from web.WriteLine("Database: {0}".WriteLine("Connecting to db\n"). a change in the database means the code will have to be modified and recompiled.config file. ASP.NET solves this problem by using the web.Database). Console. <configuration> <appSettings> <add key="DBConnect" value="server=mySqlDB.initial catalog=dbTest. ACCESSING DATABASES static void Main(string[] args) { Console."/> <appSettings> .Open(). connection. Console. The following is an extract from a web.Appsettings["DBConnect"].148 CHAPTER 12. it is not secure. connection.

strName = (string) rdr["fldCustName"].Text = id + " " + strName.Open(). // string strTmp = myReader[0]. cmDB. A Trim() is used to remove whitespace. myReader[1] then accesses the SECOND field.Connection = connection. string strSearch = "SELECT * FROM tblCustomer where fldCustName LIKE ’" + TextBox1.ExecuteReader(). the myReader[0] accesses the FIRST field of data // the selected record.Trim() + "%’".ToString(). // SQL uses a % for wildcard myReader = cmDB. string strName. .Integrated Security=True". SqlConnection connection = new SqlConnection(CON_STRING).12.Read()) { // Do something with the data // In the following code. fltBal. } myReader.CommandText = strSQL. The assumption is that a TextBox called txtSearch is used to input the search parameters. while (rdr. string strSQL = "SELECT * FROM tblCustomer WHERE" + " fldCustSurname = ’Hardy’ AND fldCustName = ’Frank’". EXAMPLES 149 while(myReader.ToString() + " " + myReader[1]. The following code shows how to access particular fields using a Data Reader. SqlDataReader rdr = cmDB. connection." + "Initial Catalog=dbCustomer.2. // Access SQL EXPRESS db and retrieve data and put field // values into variables string CON_STRING = "Data Source=ejd\\sqlexpress. // etc etc TextBox1.Close().Text. int id.Read()) { id = (int) rdr["fldCustomerID"]. SqlCommand cmDB = new SqlCommand().ExecuteReader(). cmDB. strSurname. float fltCred. A wildcard search can be achieved as follows.

connection. connection. String MyString = @"INSERT INTO tblCustomer(fldCustName. CHAPTER 12. ’" + txtSurname. fldCustSurname)" + "VALUES(’" + txtFirstName. String CON_STRING = @"Data Source=mname\sqlexpress. connection. string CON_STRING = @"Data Source=mname\sqlexpress. you would have the following statement in C#. SqlConnection connection = new SqlConnection(CON_STRING). fldCustSurname)" + "VALUES(’Angus’. It is likely that the C# programmer will have a need to extract some data from a TextBox. In the case of wanting to insert the values from two TextBoxes called txtFirstName and txtSurname.ExecuteScalar().Close().Open(). connection. MyCmd." + "Initial Catalog=dbCustomer" + ". connection). The following code shows how to edit a row in a database. String MyString = "UPDATE tblCustomer SET fldCustCred = ’1000’ " + . SqlConnection connection = new SqlConnection(CON_STRING).Text.Open(). ACCESSING DATABASES The following code shows how to insert a row into a database.Trim() + "’)".Close(). using a SQL INSERT command.Integrated Security=True".Text. and insert that value into a table. using a SQL UPDATE command. SqlCommand MyCmd = new SqlCommand(MyString.150 } rdr. ’MacBeth’)"." + "Initial Catalog=dbCustomer.Integrated Security=True".Close(). String MyString = @"INSERT INTO tblCustomer(fldCustName.Trim() + "’. either on a Windows or Web Form.

Message.Text = ex. connection). using a SQL DELETE command. string CON_STRING = "Data Source=mname\\sqlexpress. try { connection.Close().Close().2. EXAMPLES "WHERE fldCustName = ’Angus’". } finally { connection. String MyString = @"DELETE FROM tblCustomer " + "WHERE fldCustName = ’Greg’". } catch (Exception ex) { TextBox1.ExecuteNonQuery()." + "Integrated Security=True".Open().12." + "Initial Catalog=dbCustomer.. MyCmd. SqlConnection connection = new SqlConnection(CON_STRING). CATCH block for exception handling. MyCmd. 151 The following code shows how to delete data in a database. } . connection. SqlCommand MyCmd = new SqlCommand(MyString. SqlCommand MyCmd = new SqlCommand(MyString. This program uses a TRY.. connection).ExecuteScalar().

string strTmp = "Some string". The following code retrieves the data from the Session object. That leaves the problem of maintaining state between the Web Forms of a single application. HyperLink1.1 Introduction ASP.Redirect("default2. Below is some code for creating cookies.NavigateUrl = "default.NET 13. Response.NET Framework.NET applications. 13. A Query String can be created using a HyperLink control. string strRetSess = Session["sessionTmp"]. This chapter outlines some additional code that is required when programming web applications. Session["sessionTmp"] = strTmp. Of all the available .aspx?name=evan". 152 . String strTmp = Request. cookies can be used.2 State Management Web Forms can be thought of a seperate applications.NET languages.Chapter 13 ASP. The Session object can achieve this.ToString().QueryString["name"]. For the longer term storage of data.aspx"). C# is perhaps the best language to write ASP.NET is Microsoft’s Web technology built on the . The code below shows how to save a variable using the Session object. The Query String can be retrieved by using the Request object.

Value = DropDownList1.Cookies. // Cookie name String strCookieName = "Names". //Grab the cookie HttpCookie cookie = Request. we employ the following code to ensure that some code is only executed the first time a Web Form is loaded.Now. cookie. 0). 1. } A cookie can be deleted in the following manner.Expires = DateTime.AddDays(-1). //Check to make sure the cookie exists if (null == cookie) { Response.ToString().Value. passing the name into the constructor HttpCookie cookie = new HttpCookie("Names"). //Set the cookies value (In this case from a DropDownList) cookie. 0.ToString().Add(cookie).13. } else { //Write the cookie value String strCookieValue = cookie.Expires = dtNow + tsMinute. // Redirect to another Web Form Response. 153 13. //Add the cookie Response.3. TimeSpan tsMinute = new TimeSpan(0. //Set the cookie to expire in 1 minute DateTime dtNow = DateTime.aspx").Write("Cookie not found.Now. . <br><hr>"). Data from a cookie is retrieved using the Request object.Add(cookie).Cookies. Response. cookie.SelectedItem.Redirect("default2.3 Page Load In the Page Load event.Cookies[strCookieName]. PAGE LOAD //Create a new cookie.

} .Add{"Gauteng"}.Items. StateDropDownList.Items.154 CHAPTER 13.Add{"Northern Province"}. ASP.NET if(!IsPostBack) { // Code in this block will only execute once StateDropDownList.

Bibliography [1] http://www.com/csharp [2] C# Language Specification 155 .codeproject.

62 INSERT. 27 Boxing. 100 Exception Handling. 26 Arrays. 6 Worker threads. Contextual. 153 Data Provider.NET. 24 Client server model. 68 Thread. One-Dimensional. 148 Atomic. 150 Integer division. 115 binary representation. 2 Inheritence. 45 156 Namespace. 152 Structures. 37 Arrays. Multidimensional. 83. 148 Serialization. 151 Dereferencing. 152 Recursion. 25 Keywords. 45 SELECT. 127 Cookies. Jagged. 69 DELETE. 67 Pointer.NET. 105 Thue-Morse sequence. Deleting. 19 Request Object. 12 Identifiers. 26 Arrays. 146 . 40 Type conversion. 8 Delegate. 18 Preprocessor Directives. 2 Keywords. 25 ASP. 150 Using. 27 Bitwise operation. 153 Cookies. 104 Query String. 29 by reference. 11 UPDATE. 7 Floating point division. 12 Interface. 146 Arrays of Strings. 146 Data Types.Index ADO. 3 Process. 11 Operator overloading. 3 Maths. 116 XML. 81 Session Object. 68 Event. 7 Null character. 18 Enumeration. 152 Sealed. 64 Jagged arrays.

Sign up to vote on this title
UsefulNot useful