P. 1
csharp

csharp

|Views: 60|Likes:
Published by dragonjro

More info:

Published by: dragonjro on Sep 13, 2010
Copyright:Attribution Non-commercial

Availability:

Read on Scribd mobile: iPhone, iPad and Android.
download as PDF, TXT or read online from Scribd
See more
See less

10/31/2011

pdf

text

original

Sections

  • Introduction
  • CSharp Basics
  • 2.1 Introduction
  • 2.2 Basic Data Types
  • 2.3 ASCII Table
  • 2.4 Arithmetic Operations
  • The arithmetic operations are
  • 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.14 Commmand-Line Arguments
  • 2.15 Boxing and UnBoxing Types
  • 2.16 Delegates
  • 2.17 Types
  • 2.18 Reflection
  • String and StringBuilder
  • 3.1 String Class
  • 3.2 Convert Class
  • 3.3 StringBuilder Class
  • Built-in Classes
  • 4.1 DateTime Class
  • 4.2 Array Class
  • The Array class
  • 4.3 ArrayList Class
  • 4.4 ListDictionary Class
  • 4.5 Class IEnumerator
  • 4.6 Mathematics Class and Random Class
  • 4.7 Point Classes
  • 4.8 Class BitArray
  • 4.9 Object Class
  • 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
  • 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
  • Graphics
  • 7.1 Drawing Methods
  • 7.2 Color Class
  • 7.3 Button and EventHandler
  • 7.4 Displaying Images
  • 7.5 Overriding OnPaint
  • 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 117
  • 9.9 Asynchronous Programming Model
  • 9.10 Timers
  • 9.11 Interrupt and Abort

Programming in CSharp

by Willi-Hans Steeb International School for Scientific Computing email addresses of the author: steeb_wh@yahoo.com steebwilli@gmail.com whs@na.rau.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 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 4 4 6 8 9 11 15 16 17 17 19 22 24 25 26 27 27 28 29

3 String and StringBuilder 31 3.1 String Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 3.2 Convert Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 3.3 StringBuilder Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 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 4.7 Point Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Random Class . . . . . . . . . i . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36 36 37 38 39 40 40 43

4.8 4.9

Class BitArray . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44 Object Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50 50 55 57 61 62 63 64 69 69 69 71 74 76 78 81 81 84 86 88 89 95 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99 99 100 100 101 102 104 105 106 108 110 111 112 117 118 119

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

. . . . .3 User Datagram Protocol . . . . . . . . . . . . . . 122 . . . . . . . 130 11 Remoting 132 11. . . .10 Sockets Programming 10. .1 Introduction . 10. . . .1 Introduction . . 122 . . . . . . . . . . . . . . . . 123 . . . . . . . . . . . . . . . . . . . . . . . .2 Transmission Control Protocol . . . . . . . . . . . . . . . . . . . 132 Bibliography Index 141 141 iii . . . . . . . . . . . . . . . . . 10.

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

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

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

do not use the following for a class name: System Collections Forms UI . For example.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 Do avoid using class names duplicated in heavily used namespaces.

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

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

uint. sbyte. ulong float.WriteLine("Hello {0}". } else { Console. class Hello3 { public static void Main(string[] args) { if(args. // hello3.ReadLine(). CSHARP BASICS To read from the keyboard we use the method ReadLine(). byte. .WriteLine("Good Night"). int and uint are 4 bytes.2 Basic Data Types Basic (primitive) data types are bool. } Console. 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. Console.Length > 0) { Console. short. Built-in types are also string and object. The floating point number float is 4 bytes and the floating point number double is 8 bytes.127.255 and for sbyte is -128.name).6 CHAPTER 2.WriteLine("Hello {0}".args[0]). char data type (2 bytes) in C# contains Unicode characters similar to Java. The command Length returns the number of elements in the array. short and ushort are 2 bytes (16 bits). We are also using an if-else construct. decimal The range of byte is 0. double. where ushort is unsigned. string name = Console.cs using System.WriteLine("Enter your name: "). int. char.. ushort.. long. } // end Main } 2.

Char System..WriteLine(f).Double System...Byte System. // character ’a’ ASCII value 98 Console. Console. class Datatypes { public static void Main() { bool b = true.UInt32 System. sbyte d = -125.WriteLine(g).2.NET types described in the above table.WriteLine(e)..NET Type System. c++. // null character ASCII value 0 Console.Int32 System.cs using System.WriteLine(c).Int64 System. is int // unsigned byte 0. short g = -10000.UInt64 System.127 // short -32768. // ! is the logical NOT // character 2 bytes Unicode char e = ’a’. struct and class.Decimal System.Boolean System. // default integer type byte c = 255. char f = ’\0’..Int16 System.2. // datatypes.Single System.32767 (2 bytes) .255 // signed byte -128. // boolean data type Console.. Console.WriteLine(!b). Apart from the above basic types the user may define his own types using enum. BASIC DATA TYPES C# bool byte sbyte char short ushort int uint long ulong float double decimal string object .String System.UInt16 System.SByte System.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 7 At compile time the C# compiler converts the C# types into their corresponding . d--.

2. ASCII is. class Escape . Console..WriteLine(h).14159. // type conversion Console. ulong l = 3456789123. and in control devices that work with text. // float 32 bits Console. in other communication equipment.WriteLine(p). ASCII specifies a correspondence between digit bit patterns and the symbol of a written language..WriteLine(n)...89124357865678. Furthermore ’0’ is 48 and ’9’ is 57. // decimal 128 bits decimal p = (decimal) 2. uint j = 200000. int i = -100000. Console. ASCII reserves the first 32 codes (numbers 0-31 decimal) for control characters. long k = -234567899.WriteLine(j).. CHAPTER 2.2147483647 // unsigned int 0. } } Note that (data type) is the type conversion operator. ASCII codes represent text in computers.2^63-1 // unsigned long 64 bits 0. The capital ’A’ is 65 (decimal) and the small ’a’ is 97..WriteLine(m).WriteLine(i). CSHARP BASICS // unsigned short 0.WriteLine(l).8 ushort h = 20000. The null character is ’\0’. // Escape. Console.. We are doing type conversion from char -> int using the ASCII table. a seven-bit code.145.2^64-1 // default floating point number is double // (float) type conversion from double to float float m = (float) 3..WriteLine(k). meaning that it uses the bit patterns representable with seven binary digits (a range of 0 to 127) to represent character information. double n = 3.cs using System.4294967295 // signed long 64 bits -2^63. Console.. // double 64 bits Console.. Space is 32. Console.65535 (2 bytes) // signed int -2147483648.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. The type conversion operator is (data-type). strictly.

WriteLine("i1 = " + i1). The operation % provides the remainder in integer division. // carriage return int i4 = (int) c4. ARITHMETIC OPERATIONS { public static void Main() { char c1 = ’\b’. % where ++ is the increment by 1 and -. // ASCII value Console. // horizontal tab int i5 = (int) c5. *.is the decrement by −1. // 8 char c2 = ’\f’. // backspace int i1 = (int) c1. // 10 char c4 = ’\r’. // newline int i3 = (int) c3.WriteLine("i2 = " + i2). // ASCII value Console.WriteLine("i4 = " + i4). Note that we have integer division (for example 17/4 = 4) and floating point division depending on the data types.4. // ASCII value Console.WriteLine("i5 = " + i5). +. // 13 char c5 = ’\t’.4 Arithmetic Operations The arithmetic operations are ++. // ASCII value Console. // 32 } // end Main } 9 2. // ASCII value Console. // blank int i6 = (int) c6. . // ASCII value Console. // form feed int i2 = (int) c2. /.2. // 12 char c3 = ’\n’.cs using System.WriteLine("i3 = " + i3). // 9 char c6 = ’ ’.WriteLine("i6 = " + i6). -. // arithmetic. --.

WriteLine(k).WriteLine(c). // type conversion decimal p2 = (decimal) 3. // signed int int j = 15002. int r2 = 5. // type conversion decimal p3 = p1 + p2. Console. int r1 = 27. decimal p1 = (decimal) 2. // type conversion float f2 = (float) 2. int i = -100000. } } .WriteLine("r3 = " + r3). int k = i + j. sbyte d = -125. float f3 = f1*f2.145. CSHARP BASICS float f1 = (float) 3. Console.WriteLine(f3). Console. // remainder Console. int r3 = r1/r2. // signed byte d--. long m = -234567899.5. Console.WriteLine("r4 = " + r4). double d1 = 3. // signed long long n = 345.14159.10 class Arithmetic { public static void Main() { byte c = 255.WriteLine(d3).89124357865678. int r4 = r1%r2. // integer division Console. CHAPTER 2.WriteLine(d). double d2 = 4. long p = m*n.WriteLine(p3). c++.81.WriteLine(p).14159. double d3 = d1/d2. Console. Console. Console.

5. 3. } Console. else and switch use certain criteria to select a course of certain action within the program. Console.5 Control Statements Control statements control the program flow.WriteLine("Enter integer: ").WriteLine("The number is smaller than 5 or equal to 5").i<numbers.4 }.ToInt32(line). for(i=0.0. int[] x = new int[3]. else Console. class forloop { public static void Main() { double[] numbers = { 1. CONTROL STATEMENTS 11 2. 4.2.2. // myIf. string line = Console. i = System. // forloop.cs using System. selection statements such as if . class myIf { public static void Main() { int i. // convert string of digits to int if(i > 5) // if true do the next command else skip it Console.cs using System. } // end Main } The for loop applied to a one-dimensional array.i++) // Length provides length of array { sum += numbers[i].. For example.WriteLine("The number is larger than 5"). int i = 0.sum).Length.3.1.Convert.ReadLine().WriteLine("sum = {0}". // declare array and allocate memory . double sum = 0. 2.. // sum = sum + numbers[i].

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

} } // end foreach Console. class whileloop { public static void Main() { 13 . int sum = 0.Length) { sum += numbers[i]. while(i < numbers. class whileloop { public static void Main() { int[] numbers = { 1.count). // dowhileloop.2. CONTROL STATEMENTS string n = "otto". } // end Main } The while loop // whileloop. } Console.WriteLine("sum = {0}". 2. int i = 0.sum).cs using System. 4 }. foreach(string name in namelist) // keyword in { if(name == n) // compare strings for equality case sensitive { count++. } // end Main } The do-while loop applied to an array of floating point numbers.cs using System. 3.WriteLine("count = {0}".5. i++.

break.WriteLine("sum = {0}".-3.. The break statement can also be used to break out of an iteration loop.cs using System. The switch statement transfers control to one of several case-labeled statements. break. switch(c) { case ’a’: Console.3. } } // end for loop int[] numbers = { 3.i<st.Length. default: Console. 3. break.WriteLine("character is not an ’a’ or a ’b’ "). // switch.1. Console.4. execution will continue over the remaining statements in the switch block.sum).1.5.6. depending on the value of the switch expression. class Myswitch { public static void Main() { string st = "bella". int i = 0. case ’b’: Console.. 2. } while(i < numbers.WriteLine("character is a ’b’ ").4. i++.Length). . } // 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 . do { sum += numbers[i].i++) { char c = st[i].0.5 }. CSHARP BASICS double[] numbers = { 1. double sum = 0.1. for(int i=0. 4.14 CHAPTER 2.WriteLine("character is a ’a’ ").6}. else constructions. Note that if the break is omitted.

} // end switch } // end for loop } // end Main } 2. if((j%2 == 0) && (j < 10)) Console.WriteLine("number at position {0} is 6". break.WriteLine("number at position {0} is not 4 or 6".j). int k.6 Logical Operations The logical operators in CSharp. LOGICAL OPERATIONS 15 for(int j=0.Convert.cs using System.WriteLine("Enter an integer: "). . break. C++ and Java are && logical AND || logical OR ! logical NOT // logical. default: Console. string line = Console. Console. Console.j<numbers. j = System.WriteLine("The integer is either odd or larger than 10 or both"). else Console.j).WriteLine(" Enter an integer: ").WriteLine(). C.6.j++) { switch(numbers[j]) { case 4: Console.WriteLine("number at position {0} is 4". class MyLogica { public static void Main() { int j.Length.WriteLine("The integer is even and smaller than 10").ToInt32(line).j). break. case 6: Console.2.ReadLine(). Console.

ReadLine(). line = Console. } } 2. . Thus the pointer has an address and contains (as value) an address. Pointers in CSharp must be declared unsafe. n = System. if((k > 0) || (k < 0)) Console.WriteLine("The integer is nonzero"). Console. int* p = &i. int* q = &j. // Pointers1. // declare pointer and assignment to address of i int j = 15.ReadLine(). else Console. // true bool b2 = (p == q).Convert.Convert. Obtaining the value that a pointer referes to is called dereferencing. int n.WriteLine("The integer is nonzero").cs using System.ToInt32(line).ToInt32(line).WriteLine("b1 = " + b1). Console.WriteLine("The integer is zero"). class Pointers { public static unsafe void Main() { int i = 15.WriteLine("The integer is zero").WriteLine("Enter an integer: "). Console. CSHARP BASICS line = Console. else Console.WriteLine().16 CHAPTER 2. bool b1 = (i == j). if(n == 0) Console.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. The dereference operator is *. k = System.

9 Jump Statements C# also has an goto for jumping to labels. // mygoto. A recursive function is one whose definition includes a call to itself. A recursion needs a stopping condition. ulong result = fib(n). L4 if a condition is met.8 Recursion Recursion plays a central role in computer science. We use the goto to jump to the labels L1. return fib(n-1) + fib(n-2). // 15 } } We are using pointer to pass by reference (see section 2. 17 2. L2.result).WriteLine("r = " + r). } // end Main } 2. Console.8. RECURSION Console.WriteLine("b2 = " + b2). // false // dereferencing pointers int r = *q. Console. We use recursion to find the Fibonacci numbers. L3. class recur { public static ulong fib(ulong n) { if(n == 0) return 0. } // end fib public static void Main() { ulong n = 10.cs .10). if(n == 1) return 1. // recursion.2.cs using System.WriteLine("Result = {0}".

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

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

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

ref int r) { int t = r. // => s1 = yyy s2 = 111 } } The out keyword explicitely speciefies that a variable should be passed by reference to a method. rot(ref a. int b = 12. .ref int q.WriteLine("a = {0} and b = {1} and c = {2}". Console.s2).ref b.c).ref c). } public static void Main() { string s1 = "xxx". Console. int c = 17.a.s2). string s2 = "111". } public static void Main() { int a = 10. and set in that method. // passing.cs using System.2. p = q.b. r = p. PASS BY REFERENCE 21 using System. } // end Main } In the following program we pass the first argument by reference and the second by value. change(ref s1.s1.Write("s1 = {0} and s2 = {1}". public class Passing { static void change(ref string sa. q = t.10. public class Rotate { public static void rot(ref int p. PASS BY VALUE. A variable using this keyword must not be initialized before the method call. sb = "222".string sb) { sa = "yyy".

22 // Divide.cs using System;

CHAPTER 2. CSHARP BASICS

class Divider { public static int Divide1(int dividend,int divisor,out int r) { int quot = dividend/divisor; r = dividend - quot*divisor; return quot; } // end Divide1 public static void Divide2(int dividend,int divisor,out int quot,out int r) { quot = dividend/divisor; r = dividend - quot*divisor; } // end Divide2 public static void Main() { int r; int q = Divide1(123,14,out r); Console.WriteLine("Quotient = {0} and Remainder = {1}",q,r); int s; int t; Divide2(145,3,out s,out t); Console.WriteLine("Quotient = {0} and Remainder = {1}",s,t); } // end Main }

2.11

Arrays

C# supports one-dimensional arrays, multidimensional arrays (rectangular arrays) and arrays of arrays (jagged arrays). As C, C++ and Java C# arrays are zero indexed. This means the array indexes start as zero. When declaring arrays, the square bracket [] must come after the type, not the identifiers, for example int[] table. The size of the array is not part of its type as it is in the C language. Thus int[] numbers = new int[20]; In C# arrays are actually objects. System.Array is the abstract base type of all array types. The class Array contains methods for sorting and searching.

2.11. ARRAYS // myArray.cs using System; class myArray { public static void Main() { int[] numbers = { 4, 12345, 890, 23456789 }; int prod = numbers[2]*numbers[0]; Console.Write("prod = " + prod); Console.Write("\n"); int numb = Array.BinarySearch(numbers,4); Console.Write("numb = " + numb); Console.Write("\n"); double[] d = new double[3]; d[0] = 1.1; d[1] = 3.4; d[2] = 8.9; int dpos = Array.BinarySearch(d,8.9); Console.Write("dpos = " + dpos); Console.Write("\n"); string[] slist = { "otto", "uli", "carl", "marius", "jacob" }; int pos1 = Array.BinarySearch(slist,"carl"); Console.Write("pos1 = {0}",pos1); Console.WriteLine(); Array.Sort(slist); // sorting the array int pos2 = Array.BinarySearch(slist,"carl"); Console.Write("pos2 = {0}",pos2); Console.WriteLine(); for(int j=0;j<slist.Length;j++) { Console.WriteLine("{0} {1}",j,slist[j]); } } } Two-dimensional arrays. We can also create jagged arrays. // twodim.cs

23

24 using System;

CHAPTER 2. CSHARP BASICS

public class TwoDim { public static void Main() { int[][] matrix = new int[2][]; // rows matrix[0] = new int[2]; // columns matrix[1] = new int[2]; // columns matrix[0][0] = 2; matrix[0][0] = 4; matrix[1][0] = 7; matrix[1][1] = 3; int i = 1; Console.WriteLine("matrix[" + i + "][" + i + "] = " + matrix[i][i]); double[,] myarray; myarray = new double[2,3]; myarray[0,0] = 3.1; myarray[0,1] = 4.7; myarray[0,2] = 3.3; myarray[1,0] = 2.7; myarray[1,1] = 1.1; myarray[1,2] = 7.3; double r = myarray[0,1]*myarray[1,2]; Console.WriteLine("r = " + r); } // end Main }

2.12

Bitwise Operations

Consider the integer number 17 (base 10, i.e. 17 = 1 · 101 + 7 · 100 . It can be written in binary as 17 = 1 · 24 + 0 · 23 + 0 · 22 + 0 · 21 + 1 · 20 . Thus the binary representation of 17 would be 10001. If 17 is considered as data type int (32 bits) we have the binary representation 00000000000000000000000000010001 The bitwise operation in CSharp, C, C++ and Java are: & | ^ ~ AND OR (inclusive OR) XOR (exclusive OR) NOT

// bitwise.cs

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

exe) compiles a C# program it marks the Main method as the entrypoint in the generated IL code.WriteLine("k = " + k).WriteLine("j = " + j). CSHARP BASICS by 2 8 by 4 4 int m = 9. // => int k = i >> 2.26 int i = 17.WriteLine("Goodbye. } } We run the program. // multiplication by 2 Console. // multiplication by 4 Console. int n = m << 1.WriteLine("p = " + p). Comsole. When the C# compiler (csc.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. // 17 in binary 10001 int j = i >> 1.cs using System. class CommandLine { public static void Main(string[] args) { Console. // integer divison Console.WriteLine("Hello{0}". The Main method may accept an array of string as its arguments (though this is optional). // => 18 int p = m << 2. // => CHAPTER 2."). We start counting from zero. This array will always contain the command line arguments passed to the program by its user. // integer divison Console.WriteLine("n = " + n). The following program shows an application. // CommandLine. // => 36 } } 2.args[0]). for example CommandLine World .

an InvalidCastException is thrown. BOXING AND UNBOXING TYPES 27 2.7. j = (int) obj. For example int i.11). and unboxing refers to the opposite.int a. md += new MyDelegate(SecondMethod).WriteLine("i={0}". Boxing is carried out implicitly in C#.15. md("message A". so in the above statement integer i is implicitly boxed to an object and passed to the WriteLine method. 2.2.4. whereas we have to use type casting to unbox to an appropiate data type.16 Delegates A delegate essentially creates a name for a the specific type/signature of a method. One must first declare a delegate. An example for unboxing is int i. // to unbox we use type cast Typically unboxing is done in a try block. Console. Delegates are type safe function pointers.5). // declare delegate with the signature of the // encapsulated method delegate void MyDelegate(string m. If the object being unboxed is null or if the unboxing cannot succeed because the object is of a different type. The WriteLine() method requires an object. class Application { public static void Main() { MyDelegate md = new MyDelegate(FirstMethod).15 Boxing and UnBoxing Types Boxing refers to converting a value type to an object type. // boxing is implicit int j. md("message B".cs using System. // delegates.i). } // end Main . object obj = i.int b).

WriteLine("2st method: " + s2).14. int sum1 = x1 + y1. Console. string s = "xxx".cs using System. .int y2) { Console. } static void SecondMethod(string s2.int x2. } } 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 2.17 Types The typeof command is an operator. To check whether an object is compatible to a specific type is to apply the is keyword.WriteLine("sum2 = " + sum2). StringBuilder sb = new StringBuilder("123456789"). CSHARP BASICS static void FirstMethod(string s1. class myTypeof { public static void Main() { double b = 3.int y1) { Console. Console.Text. using System. int sum2 = x2 + y2.WriteLine("1st method: " + s1).int x1. It resolves at compile time and operates over a type.WriteLine("sum1 = " + sum1).28 CHAPTER 2. // myTypeof.

2.18. REFLECTION Type at = typeof(double); Console.WriteLine("at = {0}",at); Type st = typeof(string); Console.WriteLine("st = {0}",st); Type sbt = typeof(StringBuilder); Console.WriteLine("sbt = {0}",sbt);

29

if(s is string) Console.WriteLine(at); if(s is StringBuilder) Console.Write("s is of the StringBuilder"); else Console.Write("s is not of StringBuilder"); if(b is int) Console.WriteLine("b is int"); } }

2.18

Reflection

Exposing and utilizing types at runtime is called reflection. The type of an object is stored as an instance of System.Type class the reference to which can be obtained using one of the following methods. 1. From the declaration type: If declaration AType var is legal then System.Type representing AType can be obtained using the typeof operator as: Type t = typeof(AType); 2. From an instance: Type of an instance obj can be obtained using GetType method defined in System.Object as Type t = obj.GetType(); 3. From the type name within current assembly: System.Type offers a static method called GetType to obtain a Type from a fully qualified name of the type. The name will be searched in the current assembly Type t = Type.GetType("FullyQualifiedTypeName"); 4. From the type name within any assembly: First load the assembly and obtain a reference to it. This reference can be used to obtain the Type with a given name: using System.Reflection; Assembly asm = Assembly.LoadFrom("AssemblyName"); Type t = asm.GetType("FullyQualifiedTypeName"); The program showtypes.cs displays all the Types defined in an assembly whose name is passed in as first command line argument:

30 // showtypes.cs using System; using System.Reflection;

CHAPTER 2. CSHARP BASICS

class ShowTypes { public static void Main(string[] args) { Assembly asm = Assembly.LoadFrom(args[0]); Type[] types = asm.GetTypes(); foreach(Type t in types) Console.WriteLine(t); } } We would run the program as, for example showtypes datatypes.exe Pass complete path to any .NET exe or dll to see the types declared in it. The next program showmembers.cs takes the assembly name and type name as its command line arguments and displays all the members defined in that type of assembly. // showmembers.cs using System; using System.Reflection; class ShowMembers { public static void Main(string[] args) { Assembly asm = Assembly.LoadFrom(args[0]); Type t = asm.GetType(args[1]); MemberInfo[] members = t.GetMembers(); foreach(MemberInfo m in members) Console.WriteLine(m); } }

Chapter 3 String and StringBuilder
3.1 String Class

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

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

// => 3 } // end Main } 3. // => 1 Console. class stringarrays { public static void Main() { // one-dimensional array of strings string[] keywords = new string[] { "as".0]). {"2". {"3". // => in // one-dimensional array of strings string[] names = { "willi".WriteLine(names[2]). "ola".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."two"}.2. // => xena // two-dimensional array of strings string[. "if".3.cs using System. CONVERT CLASS 33 using System.0]).] strArry = {{"1". "do". public class MyConvert . "xena" }. Console.WriteLine(strArry[0. "in" }."three"}}."one"}.WriteLine(keywords[3]).WriteLine(strArry[2. 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. Console. Console.

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

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

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

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

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

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

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

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

Console. dir = line[0].ToInt32(line).0. Console.Sin(beta1)*Math. line = Console.WriteLine("The distance between {0} and {1} is {2} km".dest. // random.PI/180.Cos(beta1)*Math. if(dir == ’E’ || dir == ’e’) alpha2 = -alpha2.WriteLine("Enter the longitude of {0}: ".ReadLine().PI/180. if(dir == ’S’ || dir == ’s’) beta2 = -beta2.WriteLine("minutes: ").PI/180.ReadLine().ToInt32(line). line = Console.Cos(beta2)*Math.Sin(beta2).WriteLine("degrees: ").0.ToInt32(line). alpha2 += temp/60. Console.0.Convert. source. temp = (double) System.ReadLine().Cos(alpha1-alpha2) + Math.0. line = Console.ReadLine(). Console. Console.Convert. Console. alpha2 = (double) System.dest).42 CHAPTER 4.ReadLine(). beta1 *= Math.Convert.0. } } The next program shows an application of the Random class. temp = (double) System. line = Console.WriteLine("W/E: ").distance).cs using System. line = Console.WriteLine("N/S: ").Acos(temp). BUILT-IN CLASSES beta2 = (double) System. alpha2 *= Math. beta2 *= Math. theta = Math. alpha1 *= Math.WriteLine("minutes: "). distance = r*theta.ToInt32(line).0. Console.Convert. temp = Math.PI/180. dir = line[0]. beta2 += temp/60. class LearnRandom { public static void Main() .

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

int i.ycoord). BUILT-IN CLASSES Point q = new Point(xcoord. .Y.Collections. The constructor BitArray a = new BitArray(16). Console.WriteLine("The y coordinate is " + ycoordF). using System. where 1 is identified with true and 0 is identified with false.8 Class BitArray For dealing with bit string we use the class BitArray. Console. bool b = p.ycoordF). Console. Console. PointF pF = new PointF((float)23.WriteLine(c[i]).WriteLine("Bitarray c"). BitArray b = new BitArray(16). } } 4. // BitArrayTest.666666666667). public class BitArrayTest { static void Main() { BitArray a = new BitArray(16).i<16. b = pF. a[3] = a[4] = a[5] = true.Equals(qF). Console.3333.Equals(q). b[4] = b[5] = b[6] = true.(float)13. BitArray c = a. for(i=0. Console.WriteLine("The x coordinate is " + xcoordF). float ycoordF = pF.WriteLine(" the points are equal: " + b). float xcoordF = pF.WriteLine("Our Point is: " + pF).44 CHAPTER 4. PointF qF = new PointF(xcoordF.cs using System.X. i++) Console.WriteLine(" the points are equal: " + b).And(b). sets all elements to false.

BitArray f = d. Languages typically do not require a class to declare inheeritance from Object since the inheritance is implicit.WriteLine(d[i]). BitArray e = a.9.WriteLine("Xor d to get f"). The C# syntax is [Serializable] public class Object Public static (non-instance) members of this type are safe for multithreaded operations. for(i=0. Instance members are not guaranteed to be thread-safe. OBJECT CLASS Console.NET Framework class hierarchy and provides low-level services to derived classes.NET Framework. for(i=0. This is the ultimate superclass of all classes in the .SetAll(true).Not().Xor(g).SetAll(true)").WriteLine("f[" + i + "]=" + a[i]). a. Console. BitArray g = d.i<16.9 Object Class The Object class supports all classes in the . Console. it is the root of the type hierarchy.WriteLine("Clone c into d").i<16.WriteLine("").i++) Console.i<16.Not(). for(i=0.i++) Console. Console. .WriteLine("f[" + i + "]=" + f[i]).WriteLine("g[" + i + "]=" + g[i]).WriteLine("e[" + i + "]=" + e[i]).WriteLine("Not a"). for(i=0.4.Clone(). Console. BitArray d = (BitArray) c.WriteLine("a.i++) Console.i++) Console.i<16.i<16.i++) Console. } } 45 4. for(i=0.

Object obj2 = new Object(). // object1.WriteLine(obj1. The following code compares the current instance with another object. Derived classes can and do override some of these methods.46 CHAPTER 4.Equals(obj2)).cs using System. every method defined in the Object class is available in all objects in the system.NET Framework are derived from Object. suitable for use in hashing algorithms and data structures like a hash table.GetType() to determine whether the run-time types of the two objects are identical.support comparisons between objects Object.manufactures a human-readable text that describes an instance of the class The default constructor is called by derived class constructors to initialize state in this type.ToString . Initializes a new instance of the Object class.Equals(obj2)). public class object1 { public static void Main() { Object obj1 = new Object(). // => true } } The following example shows a Point class that overrides the Object. Console. // object2.Finalize .performs cleanup operations before an object is automatically reclaimed Object.cs using System. // => false obj2 = obj1. .generates a number corresponding to the value of the object to support the use of a hash table Object. The Object.Equals . which is derived from the Point class.Equals() method to provide value equality and a class Point3D. The method GetHashCode() serves as a hash function for a particular type.Equals() method uses Object.WriteLine(obj1. The method GetType() gets the type of the current instance.GetHashCode . Console. including Object. BUILT-IN CLASSES Since all classes in the .

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

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

9. } } 49 .4.name).WriteLine("name = " + m2. OBJECT CLASS Console.

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

myName = name. } } public int Age { get { return myAge.1. } public override bool Equals(object o) { if((myName==((Person1) o).myName) && (myAge==((Person1) o). } } public override string ToString() { return "Name = " + Name + ". } } public char Sex { get { return mySex.mySex = sex.mySex)) return true. Sex = " + Sex. this. else return false. } set { myName = value.5. WRITE YOUR OWN CLASS 51 // default constructor public Person1() { } // constructor public Person1(string name.myAge) && (mySex==((Person1) o). } set { mySex = value.int age.char sex) { this. this. } . } // declare a Name property of type string public string Name { get { return myName.myAge = age. } set { myAge = value. Age = " + Age + ".

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

The file Person. } // declare a Name property of type string public string Name { get { return myName.cs only contains the class Person and no Main() method. } 53 The class Person1 contains the Main() method.myName = name. } } public int Age { get { return myAge.mySex = sex. // default constructor public Person() { } // constructor public Person(string name. } set { myAge = value.cs using System.char sex) { this. this.int age. class Person { public string myName = "N/A". public int myAge = 0.5. // Person. WRITE YOUR OWN CLASS { return myName. public char mySex = ’n’. } public void set_Name(string value) { myName = value. } } public char Sex . this.myAge = age. } set { myName = value.1. 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.

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

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

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

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

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

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

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

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

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

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

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

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

// type conversion string n2 = ((Name) name2).string last) { FirstName = first.n2) < 0) { return -1.createDelegate().Compare(n1.Compare(n1. Here we use delegates to compare strings.callDelegate(d.n2) > 0) { return 1."calling the delegate").FirstName. MyDelegate d = c2.66 CHAPTER 5.FirstName. } } // end method CompareNames() . Class3 c3 = new Class3().object obj2). } // 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. } else if(string. // this is the delegate declaration public delegate int Comparer(object obj1.object name2) { string n1 = ((Name) name1). } public static int CompareFirstNames(object name1. public Name(string first. public class Name { public string FirstName = null.cs using System. public string LastName = null. LastName = last. c3. // type conversion if(string. // MyDelegate. OBJECT-ORIENTED PROGRAMMING class Driver { public static void Main() { Class2 c2 = new Class2(). } else { return 0.

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

WriteLine(name. names[i] = names[j]. OBJECT-ORIENTED PROGRAMMING { temp = names[i]. } // end if } } } // end method Sort public void PrintNames() { Console. } } // end method PrintNames() } . names[j] = (Name) temp. foreach(Name name in names) { Console.WriteLine("Names:\n").ToString()).68 CHAPTER 5.

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

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

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

72

CHAPTER 6. STREAMS AND FILE MANIPULATIONS

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);

6.3. TEXT FILE MANIPULATION

73

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) {

74

CHAPTER 6. STREAMS AND FILE MANIPULATIONS 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(); }

}

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)

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

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

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

bin").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> . ReadEmployee(). s.6 XML Documents The . <?xml version="1.78 CHAPTER 6. // displays emp.salary) about employees."Clerk". STREAMS AND FILE MANIPULATIONS private static void ReadEmployee() { Stream s = File.Close().Deserialize(s).NET framework provides an XML parser for reading and modifying XML documents. Console. WriteEmployee(emp).ToString() } public static void Main(string[] args) { Employee emp = new Employee("Jack". } } 6.WriteLine(emp).OpenRead("emp.44000). Given below is the file emp.name.xml containing information (id. job. Employee emp = (Employee) bf. There are five employees.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

WriteLine("Other thread: {0}".i).9. } // 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 101 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.cs the Thread t is set to the background thread .WriteLine("Main thread: {0}". while(i < 6) { Console.2.Start(). while(i < 2) { Console. THREADS thread. i++.2.2 Background Thread In the program threadtest2.i). i++. int i = 0. } // end while } // end Main static void ThreadJob() { int i = 0.

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

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

for(int i=1. } public static void Main() { Thread t = new Thread(new ThreadStart(Run)).i).Threading.i++) Console.Start().i<3.i++) Console.2. class JoiningThread { public static void Run() { for(int i=1. } . // joiningthread. t. Console.104 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 CHAPTER 9. using System. t.WriteLine("Hello {0}".Join().WriteLine("Welcome {0}".i).4 Join Methods The method Join() blocks the calling thread until a thread terminates. 9.cs using System.WriteLine("Goodbye"). PROCESSES AND THREADS At another run this could change.i<6.

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

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

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

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

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

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

for(int i=0. Console. Many applications use multiple threads. } public static void Sum2(Object o) { int sum2 = 0. An example is given below. for(int i=0. 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. using System.Increment(ref count).i<a1.Length.i++) { sum1 += a1[i]. int[] a1 = (int[]) o.Length. } } // end ThreadJob } 111 First the for loop in Main will run to the end and then the while loop will be done.WriteLine("I am in ThreadJob"). allowing us to concentrate on application tasks rather than thread management.7 Thread Pooling We can use thread pooling to make much more efficient use of multiple threads.7. i++.i<a2.9. but often those threads spend a great deal of time in the sleeping state waiting for an event to occur. Using thread pooling provides our application with a pool of worker threads that are managed by the system.cs using System. int[] a2 = (int[]) o. class ThreadsSum { public static void Sum1(Object o) { int sum1 = 0. // ThreadsSum2.Threading. } Console. depending on our application. 9.i++) .WriteLine("sum1 = " + sum1). THREAD POOLING while(i < 5) { Interlocked.

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

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

button.Text = "Count:".Add(lbl). Controls. lbl. statusIndicator = new Label(). Controls.34). counter. counter = new Label().Location = new Point(70. int currentCount.20). counter.Location = new Point(10. Random rng = new Random().Enabled = false. Test() { Size = new Size(180.Text = "Status:".Add(counter). lbl. lbl. lbl = new Label().Text = "Run". Controls. lbl.Location = new Point(10.Click += new EventHandler(StartThread).34).Add(lbl).20). CHAPTER 9.Size = new Size(50. button.58). PROCESSES AND THREADS Label lbl = new Label(). statusIndicator.10). Text = "Test". button = new Button().114 int target.Size = new Size(50.20). statusIndicator.Location = new Point(70. lbl.Add(button). button. button.10).Size = new Size(50.20). Controls.120).Add(statusIndicator).Size = new Size(100.Size = new Size(100. } void StartThread(object sender. Controls. lock(stateLock) { .20).EventArgs e) { button. lbl.Location = new Point(10.

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

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

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

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

Now).DateTime.WriteLine("Ticked at {0:HH:mm:ss.Threading. or immediately if the thread is already in that state. using System. } } 9. but less drastic. } // 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.Interrupt is similar. using System. This causes a ThreadInterruptedException exception to be thrown the next time the thread enters the WaitSleepJoin state.11.9.null.fff}". INTERRUPT AND ABORT using System.Abort aborts that thread as soon as possible.Now). // then go slow for another 10 seconds timer.Change(0.fff}".2000). 119 public class Timers { public static void Main() { Console. Calling Thread.DateTime.Threading.cs using System.3000.Sleep(10000). class SleepingThread { public static void Run() .WriteLine("Started at {0:HH:mm:ss. // Start in three seconds.11 Interrupt and Abort There are two methods in the Thread class which are used for stopping threads Abort and Interrupt. Thread.Sleep(10000).1000)) { // wait for 10 seconds Thread. then fire every second using(Timer timer = new Timer(new TimerCallback(Tick). Calling Thread. Aborting a thread which is executing unmanaged code has no effect until the CLR gets control again. // Interruptthread.

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

} } 121 .i++) { Console. } t. INTERRUPT AND ABORT t.Abort().WriteLine("Bye {0}".Start().i).9.i<1001. for(int i=1.11.

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

2.2 Transmission Control Protocol TCP is reliable connection oriented protocol. Example 1. The server on reciept of the string will display it. 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. When the server program is run it will indicate at which IPAddress it is running and the port it is listening to. send an acknowledgement which will be received by the client. Send and receive data. A socket is normally identified by an integer which may be called the socket descriptor. . 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.1 BSD Unix system in late 1981. When the connection is established the server will display the IPAddress and port from where it has accepted the connection. The client will ask for the string which is to be transmitted to the server.2 BSD Unix system in 1983 in conjunction with the TCP/IP protocols that first appeared in the 4. 123 Thus a socket is a communication mechanism. Formally a socket is defined by a group of four numbers. TRANSMISSION CONTROL PROTOCOL 5.10. Now run the client program so that we establish a connection with the server. The socket mechanism was first introduced in the 4.

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

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

class EmployeeTCPServer { static TcpListener listener.Net. System.126 CHAPTER 10. System.exe. #endif for(int i=0. On the Server side we first compile csc /D:LOG Server2.Start(). // 5 concurrent clients public static void Main() { IPAddress ipAd = IPAddress.WriteLine("Server mounted. System.Start().106. In our second example we include an xml-file (Server2. // Server2. System.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.2055). #if LOG Console.i<LIMIT.listening to port 2055").Configuration.Parse("152.84").IO. listener = new TcpListener(ipAd.i++) { Thread t = new Thread(new ThreadStart(Service)).Net. const int LIMIT = 5.config) on the Server side we can query from the Client.Threading.Sockets.40.cs using using using using using using System. SOCKETS PROGRAMMING Example 2. Next we compile the Client side csc Client2. } // end for loop } // end Main public static void Service() { while(true) . System. t.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.

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

SOCKETS PROGRAMMING The file (xml-file) Server2.128 CHAPTER 10.exe.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> .

StreamReader sr = new StreamReader(s).Net.Sockets.IO.40.10. Console.WriteLine(name). while(true) { Console.Close().cs using System. TRANSMISSION CONTROL PROTOCOL The Client2.GetStream(). 129 class Client2 { public static void Main() { TcpClient client = new TcpClient("152.2. using System.84".ReadLine()).ReadLine()). StreamWriter sw = new StreamWriter(s).Close(). } // end while s. Console.Write("Name: ").AutoFlush = true. using System. } finally { // code in finally block is guranteed to execute irrespective // whether any exception occurs or does not occur in the try block client. string name = Console. sw. } // end finally } // end Main } // end class Client2 .106.2055).WriteLine(sr.cs is given by // Client2. try { Stream s = client. sw.WriteLine(sr.ReadLine(). if(name == "") break.

class ServerUDP { public static void Main() { UdpClient udpc = new UdpClient(2055).ep). System.Send(sdata.AppSettings[name]. System.cs using using using using using System. The UDPServer1.WriteLine("Server started servicing on port 2055").sdata.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> .Configuration. udpc. SOCKETS PROGRAMMING 10.3 User Datagram Protocol UDP is not very reliable (but fast) connectionless protocol.ASCII.Text. while(true) { byte[] rdata = udpc.Net. byte[] sdata = Encoding.Sockets.Length.Net.GetBytes(job). System. if(job==null) job = "No such employee". string name = Encoding.exe.GetString(rdata).130 CHAPTER 10.Receive(ref ep). System.cs file is given by // UDPServer1.ASCII. string job = ConfigurationManager. IPEndPoint ep = null. Console. } // end while } // end Main } The xml-file UDPServer1. Example.

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

Console.Marshal(t. 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(). RemotingServices. ChannelServices.WriteLine("Server ready. IChannel c = new HttpChannel(8080).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. Usually this means the two processes are running on two different computers.RegisterChannel(c)."me"). ").ReadLine(). Console. } } 132 .Chapter 11 Remoting 11.

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

REMOTING System.Remoting.134 [Serializable] public class Counter { int count = 0. // for Http System.cs There are three main items in the process of remoting. // for Tcp Shared objects must be available to both the client and the server. The Client calls the Server using the Interface. } public int getCount() { return count.dll Server.Tcp. } } We have to import: using using using using using CHAPTER 11. Make a separate assembly for it csc /t:library Shared.Remoting.Runtime.dll file (generated from a .cs file) which is on the Client and Server side. The Interface is a . System.Http.Runtime.Remoting. .Channels.Channels. the Client and the Server. The Server provides an implementation of the Interface and makes it available to call. System.cs csc /r:Shared. The Interface. public void incCount() { count++.cs csc /r:Shared.Runtime.Remoting.dll Client.Channels. System.Runtime.

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

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

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

138 CHAPTER 11. In the present case 16. . REMOTING 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.

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

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

com/csharp 141 .Bibliography [1] http://www.codeproject.

99 Recursion. 27 by reference. 24 Boxing. 8 Worker threads. 9 Identifiers. 40 Serialization. 57 Integer division. 62 Pointer. 63 Event. 76 Structures. 17 Sealed. 64 Dereferencing. 21 Client server model. 95 Floating point division. 9 Interface. 24 Bitwise operation. 59 Jagged arrays. 2 Inheritence. 100 Thue-Morse sequence. 122 Delegate. 63 Thread. 111 142 . 35 Type conversion.Index Atomic. 22 Null character. 110 binary representation. 16 Enumeration. 16 Process. 8 Operator overloading.

You're Reading a Free Preview

Download
scribd
/*********** DO NOT ALTER ANYTHING BELOW THIS LINE ! ************/ var s_code=s.t();if(s_code)document.write(s_code)//-->