Programming in CSharp

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

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

3 String and StringBuilder 43 3.1 String Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43 3.2 Convert Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45 3.3 StringBuilder Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46 4 Built-in Classes 4.1 DateTime Class . . . 4.2 Array Class . . . . . 4.3 ArrayList Class . . . 4.4 ListDictionary Class 4.5 Class IEnumerator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48 48 49 50 51 52

i

4.6 4.7 4.8 4.9 4.10 4.11

Mathematics Class Random Class . . . Point Classes . . . Class BitArray . . Object Class . . . . Environment Class

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

52 55 56 57 58 61 63 63 69 71 75 76 77 78 83 83 83 85 88 90 93 96 96 99 101 103 104 110

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 and Enumerations 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 . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . ii

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

114 114 115 115 116 117 119 120 121 123 125 126 127

. .2 Examples . . . . . . . . . . . . . .3 Controls . 13. . . . . . . . . .1 TextBox . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13. .10 Timers . . . . . . 13. . . . . . . . . . . . .3. . . . . . . . . . . . . . . . . . . 163 163 163 164 164 165 165 165 165 165 165 166 167 168 168 iii . . . . . . 13. . . . . . . . . . . . .2 Page Lifecycle . . . . . . . 133 9. . . . . . . . . . . . . . . . . . . . . . . .3. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158 13 ASP. . . . . . . . . . . . . . . . .3. . . . . . . . . . 13. . . . . 132 9. . . . .3. . . . . . . . . . . . . .4 CheckBoxList . . . . . . . . .2 DropDownList . . 10. . . . . . . . . . . . . . . . . . . 13. . . . . . . . . . . 137 . . . . 13. .1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . .9. . . . . . . . .3. . . . . . . . . . . . . . . .1 Introduction . . . . . . . . . . . 134 10 Sockets Programming 10. . . . . . . . . . . . . . . . .3 CheckBox . . . . . . . . . .3. . .3 User Datagram Protocol . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13. 137 . . . . . . . . . . . 156 12. . . . . . . . . .6 RadioButtonList 13. . . . . . . . .3. . . . . .1 Introduction . . . . . . . . . . . . . . . .1 Introduction . . . . . . . 13. .7 Navigation . . . . . . . . . . . . . . 13. . . . . . . . . . . . . . . . . . . .2 Transmission Control Protocol . . . . . . . . . . . . . . . .5 RadioButton . . . . . . . . . . . . . 138 . . . . . . Bibliography Index . . . . . 10. . . . . . . . . . 145 11 Remoting 147 11. . . . . . . . . .11 Interrupt and Abort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .9 Asynchronous Programming Model . . . . . . . .5 Page Load . . . . . . . . . . .NET 13. . . . . . .4 State Management . 147 12 Accessing Databases 156 12. . .

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

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

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

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

4 CHAPTER 1. The . Together these form part of the . Windows Communication Foundation (WCF).NET Framework SDK.0 and 3. In order to compile . VJ#.microsoft. the most important of which are the runtime and Class Library. Pascal Common Language Specification (CLS) Common Type System (CTS) ASP. See Table 1. The .NET Framework.NET code. 2. thread management.1: .NET.5.NET Framework consists of several components. Windows XP SP2. Vista or later is installed.1 for an overview of the stack. The current version of the .NET Windows Forms XML Web Services Web Forms Data and XML Classes Base Framework Classes Common Language Runtime (CLR) Operating System Table 1. 2005 or 2008 is installed.1.NET Framework is installed automatically when Windows Server 2003. It is best to install the . Windows CardSpace and Language Integrated Query (LINQ).Net Framework is version 3. An express version of Visual Studio 2008 is available for free download from http://www. but many machines still run 1. CLR provides services that include memory management. which is Microsoft’s implementation of the Common Language Infrastructure. garbage . VB.NET Framework is also available as a separate download from Microsoft. Cobol. In addition.0. or Common Language Runtime (CLR) provides a virtual machine for the execution of . The runtime.com/Express/. Jscript.NET programs a . It is also installed when Visual Studio 2003. Windows Workflow Foundation (WF). Version 3.NET Framework Stack #define #undef #warning #error #line #region #endregion #pragma #pragma warning #pragma checksum C# cannot be run without installing the Common Language Runtime. INTRODUCTION Languages: C#.5 adds several capabilities to the stack: the Windows Presentation Foundation (WPF). The . SilverLight is a web-based subset of WPF.NET compiler must be installed. component lifetime management.

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

. In the first example this is Hello1. The method name. module. Main is often called the entry point (starting address) of the program. Main. is reserved for the starting point of a program.exe and . The most common compiler options are: • /checked Explicitly request checking for entire component • /r: Reference libraries • /out: Output file • /target: Component type (Library.exe) • /define: Define preprocessor symbols • /doc: Defines documentation output • /version: Define version • /reference: Record dependency information • /debug+ Generate debug code (creates .exe. The static modifier explains that this method works in this specific class only. rather 6 . This is also known as an executable assembly.pdb) • /main Define class which contains entry main In C# everything must be inside a class. Thus also the Main method must be contained inside a class.1 Introduction Compile and link the programs with csc filename.Chapter 2 CSharp Basics 2. In front of the word Main is a static modifier.cs This generates an execute file named filename.

// cshello. } // end Main } The namespace declaration. The System. The try block is used around statements that might throw exceptions. using System. We write to the screen using exception handling with a try catch finally block. Some common exceptions are listed here: .) goes to the next line after writing to the Console. The difference is that the Console. With the using System. for example "name".WriteLine(. This is necessary.1.) statement writes to the Console and stops on the same line.cs using System. Console.Write("midnight"). Code in a finally block is always executed.WriteLine("Good Night Egoli"). Strings are embedded in double quotes.2. To avoid fully qualifying classes throughout the program. no object instances exists. Namespaces contain groups of code that can be called upon by C# programs. but the Console.WriteLine("Hello Egoli\n"). A comment is indicated by //. declaration. The catch block defines exception handlers. We write to the screen.Console class contains a method WriteLine() and a method Write() that can be used to display a string to the console. Use it to release resources. class Hello1 { public static void Main() { Console. Note that C# is case-sensitive. An exception is an error condition or unexpected behavior encountered by an executing program during runtime.Write(. where \n provides a newline. we can use the using directive. indicates that we are referencing the System namespace. // \n newline Console. we are telling our program that it can reference the code in the System namespace without pre-pending the word System to every reference. because when a program begins. for example to close any streams or files that were opened in the try block. INTRODUCTION 7 than an instance of the class.

• System. To access command line parameters we change the signature of the Main(void) to Main(string[] args). CSHARP BASICS • System. } Console.MulticastNotSupportedException: Thrown when an attempt to combine two non-null delegates fails. • System.ArrayTypeMismatchException: Thrown when a store into an array fails because the actual type of the stored element is incompatible with the actual type of the array.DivideByZeroException • System.WriteLine("Good Night"). because the delegate type does not have a void return type.WriteLine("Hello {0}". } // end Main } .OverflowException: Thrown when an arithmetic operation in a checked context overflows. • System.cs using System. // hello2.NullReferenceException: Thrown when a null reference is used in a way that causes the referenced object to be required. class Hello2 { public static void Main(string[] args) { try { Console.InvalidCastException: Thrown when an explicit conversion from a base type or interface to derived types fails at run time. • System.ArithmeticException: A base class for exceptions that occur during arithmetic operations.DivideByZeroException: Thrown when an attempt to divide an integral value by zero occurs.WriteLine(e). The expression string[] args defines an array of strings.OutOfMemoryException: Thrown when an attempt to allocate memory (via new) fails.args[0]). such as System.8 CHAPTER 2. } catch(Exception e) { Console. • System.ArgumentException: Thrown when an argument to a method is invalid • System. • System. • System.IndexOutOfRangeException: Thrown when an attempt to index an array via an index that is less than zero or outside the bounds of the array.

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

Single System. The floating point number float is 4 bytes and the floating point number double is 8 bytes.UInt16 System.WriteLine(!b). 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.Decimal System. C# bool byte sbyte char short ushort int uint long ulong float double decimal string object . // datatypes. char data type (2 bytes) in C# contains Unicode characters similar to Java.Double System. class Datatypes { public static void Main() { bool b = true. double. Built-in types are also string and object.Int16 System. int. // boolean data type Console.cs using System. decimal CHAPTER 2.NET Type System.UInt64 System. int and uint are 4 bytes. ulong float. sbyte. where ushort is unsigned. struct and class.String System..NET types described in the above table. // ! is the logical NOT . char.Int32 System. uint..10 bool.127.SByte System.Byte System.Boolean System.UInt32 System.255 and for sbyte is -128. short and ushort are 2 bytes (16 bits). long.Int64 System.Char 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 At compile time the C# compiler converts the C# types into their corresponding . CSHARP BASICS The range of byte is 0. Apart from the above basic types the user may define his own types using enum. short. ushort. byte.

and in control devices that work with text..145. is int // unsigned byte 0.32767 (2 bytes) // unsigned short 0..2. // type conversion Console. // float 32 bits Console.. uint j = 200000.. double n = 3.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. // double 64 bits Console. // character ’a’ ASCII value 97 Console... char f = ’\0’. c++. int i = -100000.. Console. sbyte d = -125.WriteLine(k).4294967295 // signed long 64 bits -2^63.. ASCII specifies a correspondence between digit .2^64-1 // default floating point number is double // (float) type conversion from double to float float m = (float) 3. // null character ASCII value 0 Console.14159. Console...WriteLine(c).65535 (2 bytes) // signed int -2147483648. d--. short g = -10000..WriteLine(f).255 11 // signed byte -128. Console. // default integer type byte c = 255. ASCII codes represent text in computers. Console. ushort h = 20000.WriteLine(p)..89124357865678. } } Note that (data type) is the type conversion operator.WriteLine(n).2^63-1 // unsigned long 64 bits 0. 2. ASCII TABLE // character 2 bytes Unicode char e = ’a’. ulong l = 3456789123.WriteLine(i).127 // short -32768.WriteLine(e).. in other communication equipment.3. Console.WriteLine(g). Console.2147483647 // unsigned int 0. Console.WriteLine(l).WriteLine(m).WriteLine(j)... // decimal 128 bits decimal p = (decimal) 2.WriteLine(h). long k = -234567899..

// ASCII value Console. // newline int i3 = (int) c3. CSHARP BASICS bit patterns and the symbol of a written language. // backspace int i1 = (int) c1.WriteLine("i2 = " + i2). Space is 32. The null character is ’\0’. class Escape { public static void Main() { char c1 = ’\b’. // 32 } // end Main } . // 8 char c2 = ’\f’. strictly.WriteLine("i4 = " + i4). // form feed int i2 = (int) c2. The capital ’A’ is 65 (decimal) and the small ’a’ is 97. ASCII is. Furthermore ’0’ is 48 and ’9’ is 57. meaning that it uses the bit patterns representable with seven binary digits (a range of 0 to 127) to represent character information. // blank int i6 = (int) c6. // 12 char c3 = ’\n’. // horizontal tab int i5 = (int) c5.WriteLine("i5 = " + i5). // Escape. // ASCII value Console.12 CHAPTER 2. ASCII reserves the first 32 codes (numbers 0-31 decimal) for control characters. // ASCII value Console.WriteLine("i3 = " + i3). // 13 char c5 = ’\t’. The type conversion operator is (data-type). We are doing type conversion from char -> int using the ASCII table. // ASCII value Console. // carriage return int i4 = (int) c4.WriteLine("i1 = " + i1). // 9 char c6 = ’ ’. // ASCII value Console. // 10 char c4 = ’\r’.WriteLine("i6 = " + i6).cs using System. // ASCII value Console. a seven-bit code.

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

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

for(i=0. } // end for loop .1.i<numbers.0.WriteLine("sum = {0}".WriteLine(intsum). int i = 0. int intsum = 0.i++) { intsum += x[i]. // initialize sum to 0 String line.cs using System. for(i=0.sum). x[2] = 7.Length.2.Convert.ReadLine().line!="". class ForLoop { public static void Main() { int sum = 0.ReadLine()) { sum += System.Length.line=Console. double sum = 0. CONTROL STATEMENTS 15 class forloop { public static void Main() { double[] numbers = { 1. } // end Main } Another example for the for loop applied to numbers read from the keyboard. x[1] = 3.In. // forloop1. 4. 2.In.3.i<x.5. for(line=Console.ToInt32(line). // shortcut for intsum = intsum + x[i]. 3. int[] x = new int[3].2. } Console.4 }.i++) // Length provides length of array { sum += numbers[i]. // declare array and allocate memory x[0] = 4. } Console. // sum = sum + numbers[i]. Note that ! is the logical NOT and ToInt32(string) converts a string of digits to an integer.

} // end Main } The while loop // whileloop. } } // end foreach Console. int count = 0.16 CHAPTER 2. foreach(string name in namelist) // keyword in { if(name==n) // compare strings for equality case sensitive { count++."carl". int i = 0.cs using System. // foreachloop. CSHARP BASICS Console.Length) { .WriteLine(sum. int sum = 0.WriteLine("count = {0}".ToString() + "\n"). class whileloop { public static void Main() { int[] numbers = { 1. } // end Main } The foreach loop can be applied to an array of strings.cs using System. while(i < numbers."john". 3."otto" }. string n = "otto". 2. We count how often the string "otto" is in the array of strings.count)."otto". 4 }. class foreachloop { public static void Main() { string[] namelist = { "willi".

WriteLine("sum = {0}".cs using System.Length).. Note that if the break is omitted. 2. 3. The switch statement transfers control to one of several case-labeled statements. do { sum += numbers[i]. int i = 0. i++. class whileloop { public static void Main() { double[] numbers = { 1. // switch.0.5 }. The break statement can also be used to break out of an iteration loop..cs using System.1. class Myswitch { public static void Main() { .5. execution will continue over the remaining statements in the switch block. } Console. } // end Main } The do-while loop applied to an array of floating point numbers.WriteLine("sum = {0}".2.5. else constructions.sum).sum).3. CONTROL STATEMENTS sum += numbers[i]. } // end Main } 17 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 . i++. // dowhileloop. 4. depending on the value of the switch expression. Console. } while(i < numbers. double sum = 0.

6 Logical Operations The logical operators in CSharp. default: Console.18 CHAPTER 2.6. break. for(int j=0.6}. } } // end for loop int[] numbers = { 3.4. case 6: Console. class MyLogica .j). CSHARP BASICS string st = "bella". } // end switch } // end for loop } // end Main } 2. C. break.i<st.1. switch(c) { case ’a’: Console. break.j).WriteLine("number at position {0} is 4". break.WriteLine("number at position {0} is 6".WriteLine("character is a ’b’ "). break.Length. case ’b’: Console. default: Console.WriteLine("number at position {0} is not 4 or 6".WriteLine("character is a ’a’ ").-3.Length. C++ and Java are && logical AND || logical OR ! logical NOT // logical. for(int i=0.j++) { switch(numbers[j]) { case 4: Console.i++) { char c = st[i].cs using System.j<numbers.4. break.1.j).WriteLine("character is not an ’a’ or a ’b’ ").

2.7. POINTERS { public static void Main() { int j; Console.WriteLine(" Enter an integer: "); string line = Console.ReadLine(); j = System.Convert.ToInt32(line);

19

if((j%2 == 0) && (j < 10)) Console.WriteLine("The integer is even and smaller than 10"); else Console.WriteLine("The integer is either odd or larger than 10 or both"); Console.WriteLine(); int k; Console.WriteLine("Enter an integer: "); line = Console.ReadLine(); k = System.Convert.ToInt32(line); if((k > 0) || (k < 0)) Console.WriteLine("The integer is nonzero"); else Console.WriteLine("The integer is zero"); Console.WriteLine(); int n; Console.WriteLine("Enter an integer: "); line = Console.ReadLine(); n = System.Convert.ToInt32(line); if(n == 0) Console.WriteLine("The integer is zero"); else Console.WriteLine("The integer is nonzero"); } }

2.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. Thus the pointer has an address and contains (as value) an address. Obtaining the value that a pointer referes to is called dereferencing. The dereference operator is *. Pointers in CSharp

20 must be declared unsafe. // Pointers1.cs using System;

CHAPTER 2. CSHARP BASICS

class Pointers { public static unsafe void Main() { int i = 15; int* p = &i; // declare pointer and assignment to address of i int j = 15; int* q = &j; bool b1 = (i==j); Console.WriteLine("b1 = " + b1); // true bool b2 = (p==q); Console.WriteLine("b2 = " + b2); // false // dereferencing pointers int r = *q; Console.WriteLine("r = " + r); // 15 } } We are using pointer to pass by reference (see section 2.10).

2.8

Recursion

Recursion plays a central role in computer science. A recursive function is one whose definition includes a call to itself. A recursion needs a stopping condition. We use recursion to find the Fibonacci numbers. // recursion.cs using System; class recur { public static ulong fib(ulong n) { if(n==0) return 0; if(n==1) return 1; return fib(n-1) + fib(n-2); } // end fib

2.9. JUMP STATEMENTS

21

public static void Main() { ulong n = 10; ulong result = fib(n); Console.WriteLine("Result = {0}",result); } // end Main }

2.9

Jump Statements

C# also has an goto for jumping to labels. We use the goto to jump to the labels L1, L2, L3, L4 if a condition is met. // mygoto.cs using System; class Mygoto { public static void Main() { Random r = new Random(51); L3: int a = r.Next(100); int b = r.Next(100); int result; L1: Console.WriteLine("{0} + {1} =",a,b); string s = Console.ReadLine(); result = Convert.ToInt32(s); if(result == (a+b)) goto L2; Console.WriteLine("sorry you are not correct: try again"); goto L1; L2: Console.WriteLine("congratulations you are correct"); Console.WriteLine("Want to add again: Press y for yes and n for no: "); string t = Console.ReadLine(); if(t == "y") goto L3; if(t == "n") { Console.WriteLine("bye, see you next time around"); goto L4;

When an argument is passed by value. a copy of the argument is produced.10 Pass by Value. string s = new string(data).j++) { for(k=65.k<91.22 } L4: int e = 0. Pass by Reference Arguments to functions can be passed either by value or by reference. Environment.s). It is part of the class Environment. } } CHAPTER 2. CSHARP BASICS The method Exit() is used for program termination. for(i=65.c2. if(found == true) { Console.k++) { char c1 = (char) i.c3 }. and the associated .Equals(s). // password.WriteLine("Password = {0}".j. int i.i<91.k. char c3 = (char) k.cs using System.Exit(0).j<91. } } } } } } 2. char c2 = (char) j.i++) { for(j=65. char[] data = { c1. class password { public static void Main() { string password = "XYA". // converting array of char to string bool found = password.

Functions that receive variables as parameters get local copies of those variables. // 20 } // end add public static void Main() { int i = 10. // 10 } } Note that without static in method add(int): error message: An object reference is required for the nonstatic method Pitfall. Thus functions that receive pointers to variables gain access to the original variables associated with the pointers. pass by reference. change in the parameter also alter the original argument.cs using System.int* r) .add(int). add(i). Console. i = n.int* q. not the originals. changes to the parameter variable will have no effect on the original argument value. PASS BY REFERENCE 23 parameter is the same as a local variable for the function. The alternative. When arguments are passed by reference. is indicated by the presence of the keyword ref in the argument list. // Pitfall. the parameter variable is an alias for the argument value. // pointers2. In C# we can also use pointers and the dereference operator to pass by reference. In the next program we use pointers to pass by reference.10.2. Thus. This means.WriteLine("i inside function add = " + i). In the next program we pass by value. public class Pitfall { public static void add(int i) { int n = i + i.WriteLine("i in Main = " + i). PASS BY VALUE. Console.cs using System. We rotate integer numbers. public class Rotate { public static unsafe void rot(int* p.

&b. int b = 12.a. int b = 12.cs using System.a.ref c). rot(&a.cs using System. } public static void Main() { int a = 10. public class Passing { static void change(ref string sa. rot(ref a.string sb) .&c).ref int r) { int t = r. Console. q = t. *r = *p.b.WriteLine("a = {0} and b = {1} and c = {2}".ref int q. CSHARP BASICS public static unsafe void Main(string[] args) { int a = 10. // references. We rotate three integers. public class Rotate { public static void rot(ref int p.WriteLine("a = {0} and b = {1} and c = {2}". int c = 17. } // end Main } In the following program we pass the first argument by reference and the second by value.24 { int t = *r.b. r = p. // passing. *q = t.c). } // end main } In the following program we use the keyword ref to pass by reference. *p = *q.c). int c = 17.ref b. } CHAPTER 2. p = q. Console.

out int quot.out r). class Divider { public static int Divide1(int dividend. Console. int s. // => s1 = yyy s2 = 111 } } The out keyword explicitely speciefies that a variable should be passed by reference to a method. string s2 = "111".2. and set in that method.int divisor.Write("s1 = {0} and s2 = {1}". } // end Divide1 public static void Divide2(int dividend.r).WriteLine("Quotient = {0} and Remainder = {1}".cs using System. change(ref s1. PASS BY VALUE. PASS BY REFERENCE { sa = "yyy". } 25 public static void Main() { string s1 = "xxx".s2).int divisor. // Divide.s2). } // end Divide2 public static void Main() { int r.quot*divisor.out int r) { int quot = dividend/divisor. A variable using this keyword must not be initialized before the method call. r = dividend .10. .quot*divisor.s1. return quot.q. Console. int t. r = dividend . int q = Divide1(123.out int r) { quot = dividend/divisor. sb = "222".14.

11 Arrays An array is a data structure that contains a number of variables. 2. int prod = numbers[2]*numbers[0]. // myArray. Console. These are accessed through computed indices.8. C++ and Java C# arrays are zero indexed. 12345. 1.Write("\n").26 CHAPTER 2.Write("dpos = " + dpos). d[1] = 3. 3.Array is the abstract base type of all array types. This means the array indexes start as zero.1. d[0] = 1.3. C# supports one-dimensional arrays. . We can initialise arrays very simply: int[] numbers = {0.9). System.Write("numb = " + numb). Console. not the identifiers.t). The size of the array is not part of its type as it is in the C language. 890.cs using System. 5}. This is identical to the complete initialisation statement: int[] numbers = new int[] {0. Console.out s. int dpos = Array. The class Array contains methods for sorting and searching.BinarySearch(d. Console. } // end Main } 2. for example int[] table. As C.9. class myArray { public static void Main() { int[] numbers = { 4. the square bracket [] must come after the type.4.s. When declaring arrays. 3. 5}.out t). 1. Thus int[] numbers = new int[20].4). 2.WriteLine("Quotient = {0} and Remainder = {1}". int numb = Array. Console. double[] d = new double[3]. d[2] = 8. 23456789 }. In C# arrays are actually objects.Write("prod = " + prod). Console. multidimensional arrays (rectangular arrays) and arrays of arrays (jagged arrays).BinarySearch(numbers. CSHARP BASICS Divide2(145.Write("\n").

ARRAYS Console. 2}. 4. The length of each dimension of the array is determined by the number of elements at the corresponding nesting level in the array initializer. string[] slist = { "otto". numbers[0.BinarySearch(slist. Thus the example above creates a two-dimensional array with a length of five for the leftmost dimension and a length of two for the rightmost dimension. numbers[4.2.0] numbers[1. "marius". which are arrays of arrays. 17}. Console. . 16. numbers[1. "carl". The outermost nesting level corresponds to the leftmost dimension. for(int j=0.WriteLine().Sort(slist). Console. 12.pos2).WriteLine().2]."carl").Write("\n").0] numbers[2. numbers[2.1] = 14.Length.j<slist. 6}. 10}. "uli". Array. // sorting the array int pos2 = Array. Console. {4. The innermost nesting level corresponds to the rightmost dimension.0] numbers[3. For example int[. "jacob" }. Console. 8. {12.j.] numbers = {{0.BinarySearch(slist. } } } 27 To create multidimensional arrays the array initializer must have as many levels of nesting as there are dimensions in the array.1] = 6.1] = 10. 18}}. {8. and initialises the array with: numbers[0. {16.Write("pos2 = {0}". The element arrays do not all have to be the same.pos1).11.1] = 18.WriteLine("{0} {1}".slist[j])."carl"). numbers[3.1] = 2.0] = = = = = 0. We can also create jagged arrays.j++) { Console.Write("pos1 = {0}".0] numbers[4. Thus: int[.] numbers = new int[5. int pos1 = Array.

Console.3. myarray[1. double r = myarray[0.1] = 4. It can be written in binary as 17 = 1 · 24 + 0 · 23 + 0 · 22 + 0 · 21 + 1 · 20 .e.1.1]*myarray[1. } // end Main } 2. If 17 is considered as data type int (32 bits) we have the binary representation 00000000000000000000000000010001 The bitwise operation in CSharp. Thus the binary representation of 17 would be 10001. myarray[0.7.] myarray. // rows matrix[0] = new int[2]. matrix[1][1] = 3. myarray[0.1. myarray[0.cs using System.WriteLine("r = " + r). int i = 1.3]. // columns matrix[0][0] = 2.28 // twodim.0] = 3.3.2] = 3. 17 = 1 · 101 + 7 · 100 .12 Bitwise Operations Consider the integer number 17 (base 10.2]. // columns matrix[1] = new int[2].0] = 2. CSHARP BASICS public class TwoDim { public static void Main() { int[][] matrix = new int[2][].1] = 1. myarray[1. myarray[1. CHAPTER 2.7. i. matrix[0][0] = 4. C++ and Java are: & | ^ ~ AND OR (inclusive OR) XOR (exclusive OR) NOT . matrix[1][0] = 7. Console. myarray = new double[2.2] = 7.WriteLine("matrix[" + i + "][" + i + "] = " + matrix[i][i]). double[. C.

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

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

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

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

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

Generics introduce . using System.NET exe or dll to see the types declared in it.GetMembers(). using System. // showmembers. The next program showmembers. Type[] types = asm. foreach(Type t in types) Console.Reflection.exe Pass complete path to any .LoadFrom(args[0]).WriteLine(t). CHAPTER 2. MemberInfo[] members = t. } } We would run the program as.cs takes the assembly name and type name as its command line arguments and displays all the members defined in that type of assembly.GetType(args[1]).WriteLine(m). } } 2. They were introduced in version 2.cs using System.19 Generics C# Generics are similar to C++ Templates.cs using System. class ShowMembers { public static void Main(string[] args) { Assembly asm = Assembly.LoadFrom(args[0]).34 // showtypes. foreach(MemberInfo m in members) Console.GetTypes().0 of the C# language and the common language runtime (CLR). for example showtypes datatypes. Type t = asm.Reflection. CSHARP BASICS class ShowTypes { public static void Main(string[] args) { Assembly asm = Assembly.

bool b0 = stackint.Push(8).Contains(11).NET Framework the concept of type parameters. Some of the classes in System. int i = stackint. // MyStack0. . // 8 stackint.Generic.Collection.Push(11).Generic are: Dictionary<TKey. bool b1 = stackint. Console.2.Contains(8). It shows how the Push and Pop methods are used.WriteLine("b0 = " + b0).TValue> Stack<T> represents a collection of keys and values represents a doubly linked list represents a strongly typed list of objects represents a firs-in.TValue> LinkedList<T> List<T> Queue<T> SortedDictionary<TKey.Generic namespace.WriteLine("i = " + i). // false Console. stackint. The . This makes it possible to design classes and methods that defer the specification of one or more types until the class or method is declared and instantiated.Collections.Pop().NET Framework class library contains several new generic collection classes in the System. first out collection of objects represents a collection of key/value pairs that are sorted on the key represents a varaible size last-in first-out collection of instances The first example shows an application of Stack<T>. Console. class MyStack0 { public static void Main() { Stack<int> stackint = new Stack<int>(). GENERICS 35 to the . stackint.cs using System. using System.Push(5).Collections.WriteLine("b1 = " + b1).19.

int m) { if(k==m) { _permutations. stackstring. Console.ref char b) { if(a==b) return.ref list[i]). b ^= a. } else { for(int i=k. using System. public class Test { private static void Swap(ref char a.ref list[i]).i++) { Swap(ref list[k].Count. using System.36 CHAPTER 2. Permute(list.int k. // using XOR operation for swapping } private static List<string> _permutations = new List<string>(). // 11 Stack<string> stackstring = new Stack<string>(). int r = stackstring. // permutation.WriteLine("j = " + j).m). stackstring. // Recursive Function private static void Permute(char[] list.WriteLine("r = " + r). } } .Push("Baab").Generic.Collections.Add(new string(list)). // Peek does not Pop Console. a ^= b.Push("Abba").Collections. CSHARP BASICS int j = stackint.k+1.Peek(). // 2 } // end Main } The next program shows an application of List<T>. The method Add will add an element to the List.cs using System.i<=m. Swap(ref list[k]. a ^= b.

0.cs using using using using System.Length-1).Generic.TValue>.19.i++) { if(Char.Message).WriteLine(perm). Permute(list. System.2.i<str.Length.list. else sb.Append(_dict[str[i]]). } return sb. System. } } catch (Exception ex) { Console. foreach(string perm in _permutations) { Console.WriteLine("Error: " + ex.ToString().char>(). System.char> _dict = new Dictionary<char. private static string Substitution(string str) { StringBuilder sb = new StringBuilder().Collections.Collections. 37 public class Test { private static Dictionary<char. for(int i=0. char[] list = str.Text. GENERICS } [STAThread] static void Main(string[] args) { try { string str = "ola".ToCharArray().IsWhiteSpace(str[i])) sb. // Dictionary1.Append(str[i]). } } // end Main } The next program shows an application of Dictionary<TKey. } .

38 CHAPTER 2. TValue pairs in the SortedDictionary.i++) { _dict[a[i]] = b[i].WriteLine("Error: " + ex. // SOHDVH FRQILUP UHFHLSW Console.string> items = new SortedDictionary<int.string>(). class MyDictionary { // declare key dictionary object public static SortedDictionary<int.Generic.TValue> is given in the next program. // MyDictionary.Collections.Message).Length. CSHARP BASICS [STAThread] static void Main(string[] args) { try { // Build the dictionary // original alphabet A: // A B C D E F G H I J K L M N O P Q R S T U V W X Y Z string a = "ABCDEFGHIJKLMNOPQRSTUVWXYZ". } } } An application of the SortedDictionary<TKey. TValue element to the SortedDictionary. // substitution alphabet B: // D E F G H I J K L M N O P Q R S T U V W X Y Z A B C string b = "DEFGHIJKLMNOPQRSTUVWXYZABC". } string res = Substitution("PLEASE CONFIRM RECEIPT"). The method Count will find the number of TKey.cs using System.i<a. for(int i=0. } catch (Exception ex) { Console. The method Add will add a TKey. using System.WriteLine("Result=" + res). static void Main(string[] args) { .

"bulli"). } .name: {1:k}".Keys.WriteLine("{0}. } public T Pop() { return (StackPointer > 0) ? StackArray[--StackPointer] : StackArray[0]. } public void Push(T x) { if(StackPointer < MaxStack) StackArray[StackPointer++] = x. class MyStack<T> { int MaxStack = 20. bool b2 = items.ContainsKey(7). items.Generic.Count.i. It shows how the Pop and Push methods are implemented and used // MyStack1.Collections."willi"). ICollection<int> k = items.Add(1. } } 39 We can also write our own generics. An example for the stack is given below.ContainsValue("ola"). public MyStack() { StackArray = new T[MaxStack].items[i]).2.Add(2.19."ola").cs using System. items.Add(7. int no = items.WriteLine("b2 = " + b2).WriteLine("b1 = " + b1). Console. Console. GENERICS items.WriteLine("no = " + no). Console. T[] StackArray. using System. int StackPointer = 0. bool b1 = items. foreach(int i in k) Console.

Two examples are given below for a one-dimensional array and a two-dimensional array. stackint. // Baab Abba } // end Main } 2.40 CHAPTER 2.StackArray[i]).cs using System.i--) Console. Indexers have the same this and have a set of arguments in rectangular brackets. stackstring.Print(). stackint.20 Indexers An indexer is a member that enables an object to be indexed in the same way as an array (one or higher dimensional). stackstring. // 5 MyStack<string> stackstring = new MyStack<string>(). } } .Push("Abba"). CSHARP BASICS public void Print() { for(int i=StackPointer-1. stackint. public class Number { double[] Numbers. int i = stackint.WriteLine("Value: {0}".Push(5). // indexers1.Push(8).Pop().Push("Baab"). } } public class MainClass { public static void Main() { MyStack<int> stackint = new MyStack<int>().i>=0. public double this[int i] { get { return Numbers[i]. stackstring.Print().

] Numbers.2.0]=8. } } public Number() { Numbers=new double[3.24.0]=1.WriteLine().14. } } .14. Numbers[2. public class Number { double[. Numbers[1. Numbers[0.23.1]=7.i<3.j]. public double this[int i.i++) Console.1]=7. Numbers[0] = 1.23. Numbers[0. INDEXERS public Number() // default constructor { Numbers = new double[3]. Console.34. Numbers[1. for(int i=0. Numbers[0. Numbers[2.20.cs using System.nbr[i]).2]=5.int j] { get { return Numbers[i.2]=2.23. Numbers[1] = 3. Numbers[1.56.83. } // end Main } // end class MyMain // indexers2. } // end class Number 41 } public class MyMain { public static void Main() { Number nbr = new Number().83.43.3].WriteLine("Number {0}:{1}". 1+1.54. Numbers[2. Numbers[2] = 2.0]=4.2]=9.1]=3.

} Console.j]).42 CHAPTER 2. for(int i=0.{1}: {2}".j++) Console. CSHARP BASICS public class MyMain { static void Main() { Number nbr = new Number().WriteLine("Number {0}.i<3.nbr[i. } // end Main } .j.i.WriteLine().i++) { for(int j=0.j<3.

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

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

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

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

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

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

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

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

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

Console. Memebers are MoveNext. so we cannot create an object of type Math.cs using System."two"}. where T is the yield type of the iterator block. It implements System. IEnumerator sEnum = strArry. {"3".Current). Instead. while(sEnum.Write(" {0}". .] strArry = {{"1". using System.52 } } // end Main() } CHAPTER 4. we use the members and methods with the class name.MoveNext()) Console.IDisposable. all the classes and data members are static.Write("The elements of the array are: ").6 Mathematics Class The Math class is sealed. // Enumerator. The following table shows a partial list of the Math methods. Current and Dispose.GetEnumerator(). {"2".Collections. A sealed class cannot be used for inheritance.Collections. Additionally."one"}."three"}}. PI and E.sEnum. public class ArrayGetEnumerator { public static void Main() { string[. } } 4. The method public virtual IEnumerator GetEnumerator() returns a System.5 Class IEnumerator An enumerator object implements IEnumerator and IEnumerator < T >. BUILT-IN CLASSES 4. The Math class also includes two constants.IEnumerator for the current instance.

. // distance. alpha2.6. dest. Console. source = Console. x2) Smaller of the two arguments Pow(x1.ReadLine(). distance. string source. class Distance { public static void Main() { double r = 6371. MATHEMATICS CLASS Method Abs(x) Atan(x) Returns Absolute value of x Argument Return Data Type Data Type Overloaded Return matches argument type Double Double Double Double Double Overloaded Overloaded Double Overloaded Double Double Double Double Double Double Return matches argument type Return matches argument type Double Return matches Double Double Double 53 Angle in Radians whose tangent is x Cos(x) Cosine of x where x is in radians Exp(x) Value of e raised to the power of x Log(x) Natural log of x. x2) Larger of the two arguments Min(x1. char dir.2). line.cs using System. y) Value of x rounded to y decimal places Sin(x) Sine of x where x is in radians Sqrt(x) Square root of x where x <= 0 Tan(x) Tangent of x where x is in radians For example. double xr = Math. x2) Value of x1 raised to the power of x2 Round(x.Round(x.4. beta2. beta1.1415. double alpha1. temp. theta. to round a double to 2 significant digits: double x = 3.WriteLine("Enter the name of the source: "). where x >= 0 Max(x1.0.

Console. beta2 = (double) System.source).ReadLine().dest). Console.WriteLine("N/S: ").ToInt32(line).ToInt32(line). BUILT-IN CLASSES Console. temp = (double) System. line = Console.WriteLine("minutes: ").ToInt32(line).ReadLine().ReadLine(). alpha1 += temp/60. Console.ToInt32(line). Console.WriteLine("degrees: ").Convert. temp = (double) System.WriteLine("minutes: "). beta2 += temp/60.WriteLine("Enter the longitude of {0}: ". line = Console. beta1 += temp/60. Console. Console.WriteLine("minutes: ").54 CHAPTER 4. .WriteLine("Enter the name of the destination: ").Convert. Console. Console. temp = (double) System.ReadLine(). line = Console. dest = Console.ReadLine(). line = Console. line = Console.ReadLine(). line = Console. dir = line[0]. alpha1 = (double) System.Convert.ReadLine().ToInt32(line). Console.ReadLine(). if(dir == ’E’ || dir == ’e’) alpha1 = -alpha1.Convert. if(dir == ’S’ || dir == ’s’) beta1 = -beta1. line = Console.WriteLine("N/S: ").ReadLine().ReadLine(). Console. line = Console.Convert.WriteLine("Enter the latitude of {0}: ". Console.0.ToInt32(line). if(dir == ’S’ || dir == ’s’) beta2 = -beta2.ReadLine(). source).Convert.WriteLine("W/E: ").WriteLine("degrees: "). line = Console. dir = line[0].WriteLine("minutes: ").ReadLine(). dir = line[0]. Console.Convert. alpha2 = (double) System.ToInt32(line).WriteLine("degrees: ").ToInt32(line).0. Console. temp = (double) System.0.WriteLine("Enter the latitude of {0}: ".Convert. line = Console.dest).WriteLine("Enter the longitude of {0}: ". Console.WriteLine("degrees: "). beta1 = (double) System. Console. line = Console.

Cos(beta1)*Math.1)").distance).r. . // random.0. temp = Math.Sin(beta2).10)"). RANDOM CLASS alpha2 += temp/60. line = Console.cs using System. for(int i=0.1)").i++) Console.Sin(beta1)*Math. r.WriteLine("W/E: "). sequence(no seed.Cos(alpha1-alpha2) + Math.4.limit 0.WriteLine("Random for(int i=0.WriteLine(). sequence(no seed.i<10.0..int. if(dir == ’E’ || dir == ’e’) alpha2 = -alpha2. Console. theta = Math.Next()).WriteLine("random Console.r. source.i<10. sequence in byte array(no seed.7 Random Class The next program shows an application of the Random class.0.100)).i++) Console. beta2 *= Math.i<10.r.NextDouble()).WriteLine("random Console.WriteLine("Random for(int i = 0. no: {0}". no: {0}".limit 50.i++) Console. } } 55 4.limit 0. distance = r*theta.PI/180.Cos(beta2)*Math. no: {0}". class LearnRandom { public static void Main() { Random r = new Random().PI/180.PI/180.WriteLine("random Console..7. beta1 *= Math. no: {0}".0.limit 0.i<10. limit 0.100)").Next(50.Acos(temp).MaxVal)"). Console.PI/180..WriteLine("The distance between {0} and {1} is {2} km".NextBytes(b). dir = line[0].ReadLine().WriteLine("random Console.WriteLine("Random byte[] b = new byte[5].0.dest. sequence(no seed. alpha2 *= Math.WriteLine("Random for(int i=0. alpha1 *= Math..i++) Console..Next(10)).r. sequence(no seed.WriteLine("Random Console. Console.

WriteLine("random byte: {0}". Console. // pointt. int xcoord = p.Forms. } } 4. } } . Console.WriteLine("The y coordinate is " + ycoord). float ycoordF = pF. class PointTest { public static void Main() { Point p = new Point(23.i++) Console.WriteLine("The y coordinate is " + ycoordF).WriteLine("The x coordinate is " + xcoord).666666666667).WriteLine("Our Point is: " + p).Drawing.Length.Windows. Console. using System. int ycoord = p.i<b. Console. BUILT-IN CLASSES for(int i=0.8 Point Classes The Point structure represents an ordered pair xy of integers. b = pF.and y.X. bool b = p.WriteLine(" the points are equal: " + b).ycoordF). using System.cs using System. Point q = new Point(xcoord. PointF qF = new PointF(xcoordF. Console.b[i]).WriteLine("Our Point is: " + pF).Y.13).(float)13.56 CHAPTER 4.coordinates that define a point in a two-dimensional plane.WriteLine("The x coordinate is " + xcoordF).3333. Console.WriteLine(" the points are equal: " + b). Console. float xcoordF = pF. PointF pF = new PointF((float)23. The PointF structure represents an ordered pair of floating point x.ycoord). Console.Equals(qF).Y.X.Equals(q).

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

it is the root of the type hierarchy. Console. The method GetHashCode() serves as a hash function for a particular type. for(i=0. BitArray f = d. Languages typically do not require a class to declare inheeritance from Object since the inheritance is implicit. including Object.i<16.generates a number corresponding to the value of the object to support the use of a hash table Object. every method defined in the Object class is available in all objects in the system.i++) Console.Equals .10 Object Class The Object class supports all classes in the .WriteLine("g[" + i + "]=" + g[i]).NET Framework are derived from Object. } } 4.Finalize . .NET Framework. BUILT-IN CLASSES BitArray g = d.58 CHAPTER 4.WriteLine("f[" + i + "]=" + f[i]).ToString . Instance members are not guaranteed to be thread-safe.i++) Console.performs cleanup operations before an object is automatically reclaimed Object. Initializes a new instance of the Object class. This is the ultimate superclass of all classes in the .GetHashCode . suitable for use in hashing algorithms and data structures like a hash table.support comparisons between objects Object.Xor(g).i<16.Not().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.NET Framework class hierarchy and provides low-level services to derived classes. Derived classes can and do override some of these methods.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. for(i=0. Since all classes in the .

The following code compares the current instance with another object.4. y. OBJECT CLASS The method GetType() gets the type of the current instance.int Y) { this.x = X.GetType()) return false. The Object. return (x == p. Object obj2 = new Object(). // => true } } 59 The following example shows a Point class that overrides the Object. Console.WriteLine(obj1. Console. class Point : Object { protected int x. // object2.GetType() to determine whether the run-time types of the two objects are identical.Equals(obj2)). this. } public Point(int X.x = 0.Equals() method uses Object.Equals(obj2)).y).y = 0.x) && (y == p.y = Y.Equals() method to provide value equality and a class Point3D. public Point() { this. this. // => false obj2 = obj1. Point p = (Point) obj. which is derived from the Point class. public class object1 { public static void Main() { Object obj1 = new Object().cs using System. // object1. } public override bool Equals(Object obj) { // check for null and compare run-time types if(obj == null || GetType() != obj.cs using System. } .WriteLine(obj1.10.

Equals(obj) && z == ((Point3D) obj).int Z) { this.GetHashCode().Equals(p4).WriteLine("h1 = " + h1).9).8). BUILT-IN CLASSES public override bool Equals(Object obj) { return base.GetHashCode() ^ z.6.WriteLine("b1 = " + b1). Point3D p3 = new Point3D(5. int h1 = p1.7).x = X. public Point3D(int X.GetHashCode().Equals(p2). Console. } public override int GetHashCode() { return base. Console. Console.y = Y. } } The method protected object MemberwiseClone(). this.9). } // ^ XOR operation } // end class Point class Point3D : Point { int z. } CHAPTER 4. bool b2 = p3.WriteLine("b2 = " + b2). Point3D p4 = new Point3D(5.WriteLine("h2 = " + h2). bool b1 = p1. this.z.60 public override int GetHashCode() { return x^y. Point p2 = new Point(6.int Y. int h2 = p3. .6. } } // end class Point3D public class object1 { public static void Main() { Point p1 = new Point(5.z = Z. Console.

// performs a shallow copy of m1 and assign it to m2 MyDerivedClass m2 = (MyDerivedClass) m1. The .name).MemberwiseClone(). public int age.e. The method GetCommandLineArgs() returns a string array containing the command line arguments of the current process. The class is sealed. and means to manipulate.MemberwiseClone(). SystemDirectory provides as string the fully qualified path of the system directory. Version gets a Version object that describes the major. CurrentDirectory provides the directory from which this process starts. } class MyDerivedClass : MyBaseClass { public static void Main() { // create an instance of MyDerivedClass and assign values // to its fields MyDerivedClass m1 = new MyDerivedClass(). the current environment and platform.11. it cannot be inherited. m1. Console. public string name.age = 42. i. class MyBaseClass { public static string CompanyName = "KXK".WriteLine("name = " + m2. ENVIRONMENT CLASS 61 creates a shallow copy of the current object. and revision numbers of the common language runtime. } } 4. CommandLine provides the command line for this process. The following code shows how to copy an instance of a class using Object. minor. i.WriteLine("age = " + m2.e. it returns a shallow copy of the current object.4.cs using System. StackTrace provides current stack trace information.age).name = "John". ExitCode gets or sets the exit code of the process. build. // object3. Console.11 Environment Class The Environment class provides information about. m1. TickCount provides the number of milliseconds the time passed since the system started.

// 2. // true Console.StackTrace.SystemDirectory.WriteLine("t = " + t).. at MyEnviro. Console.Version. Console.WriteLine("ex = " + ex). if(x==i) Environment.WriteLine("comline = " + comline). Console..WriteLine("cd = " + cd). // enviro string cd = Environment. // at System.Exit(0). // C:\csharp int ex = Environment. } } .. // 0 string st = Environment.Main() string sd = Environment. Console.62 CHAPTER 4.WriteLine("did we reach this point?"). // enviro. Console.312 string com = Environment. Console. class MyEnviro { public static void Main() { object ver = Environment. Console.CommandLine. BUILT-IN CLASSES method Exit() terminates this process and gives the underlying operating system the specified exit code.50727.WriteLine("com = " + com).GetCommandLineArgs(). // C:\Windows\System32 int t = Environment.cs using System.Environment . // System.TickCount. int x = 15/2. . // 300223 string[] comline = Environment.. The class also contain the methods ToString and Equals.0. Console..String[] int i = 7.WriteLine("st = " + st).CurrentDirectory.WriteLine("sd = " + sd).ExitCode.WriteLine("ver = " + ver).

Constructors are methods that are invoked when objects are instantiated. The term passing a message to an object means invoking its operation. Polymorphism refers to the ability of objects to use different types without regard to the details. no arguments are required.1 Write your own class In CSharp we can write our own class. Each object holds some data (fields or attributes) as defined by its class. Object-oriented programming is essentially programming in terms of smaller units called objects. Generally the data is hidden within the objects (instances) and can be accessed only through functions defined by its class (encapsulation). no return type. A Private Constructor prevents unwanted objects from being created. Properties act like methods to the creator of the class but look like fields to the client of the class. defining the class) is called abstraction. A Default Constructor Generated by compiler if none exists. The process of deciding which attributes and operations will be supported by an object (i.e. One or more objects (instances) can be created from a class by a process called instantiation. We say the state of the object is defined by the attributes it supports and its behaviour is defined by the operations it implements. All objects are created using new. The CLR defines one.Chapter 5 Object-Oriented Programming 5. C# also introduces properties. all fields are initialized to zero. An object oriented program is composed of one or more objects. Note that writing any constructor stops default creation. have public accessibility. Instance 63 . The class also defines a set of functions (also called methods or operations) which can be invoked on its objects. but it is better practice to code the constructors that are required. Sometimes the set of operations supported by an object is also referred to as the interface exposed by this object. They have the same name as the class.

Static methods can be called. mySex. } // declare a Name property of type string public string Name { get { return myName. It cannot have parameters.myAge = age. class Person1 { private string myName = "N/A". Commonly used to implement procedural functions. } set { myName = value.char sex) { this. A default constructor may look like the following example.cs using System. These private data members are only visible inside the body of class Person1. Thus we have three attributes: myName. this. // default constructor public Person1() { } // constructor public Person1(string name. // Person1.int age. It is used to initialize static members and is guaranteed to be called before instance constructor. private int myAge = 0.myName = name. this. The Person is described by his name. Use this to declare an access modifier. OBJECT-ORIENTED PROGRAMMING methods cannot be called.64 CHAPTER 5. } } . public Person1() { } The following program shows an example for class Person. private char mySex = ’n’.mySex = sex. A Static Constructor is called by class loader at run time. myAge. age and sex.

Age = " + Age + ". } } public char Sex { get { return mySex. } public override bool Equals(object o) { if((myName==((Person1) o).Age = 99.person1).myAge) && (mySex==((Person1) o). Sex = " + Sex. } set { mySex = value.{0}". // Set some values on the person object person1.Name = "Jane".Name = "Joe".WriteLine("Person details .Name = "Jane". Person1 person2 = new Person1(). } set { myAge = value.person2).mySex)) return true. person2. 65 .WriteLine("Person details .5.myName) && (myAge==((Person1) o).Age = 31. Console. } } public override string ToString() { return "Name = " + Name + ".Sex = ’f’. } public static void Main() { // create a new Person object using default constructor Person1 person1 = new Person1().{0}". Console. person1. person2. person1.Sex = ’m’. WRITE YOUR OWN CLASS public int Age { get { return myAge. Person1 person3 = new Person1(). person3. else return false.1. person2.

mySex). person3. .WriteLine("Person details: " + person4.Age = 31.23. To access these variable outside the class we use the special property methods Name. Age.WriteLine("same person = " + same).WriteLine("sex of person[1]: " + pmany[1].cs only contains the class Person and no Main() method.myName). The CSharp compiler translates for example the Name property to a pair of methods.Sex = ’f’. Console. pmany[0] = new Person1("Carl". myAge.WriteLine("name of person[0]: " + pmany[0].person3). and Sex. These variable are visible only inside the body of class Person1. } The class Person1 contains the Main() method. OBJECT-ORIENTED PROGRAMMING person3. class Person { public string myName = "N/A".Equals(person3). The file Person. Console. public int myAge = 0.66 CHAPTER 5. // Person. Console.42.’m’). namely public string get_Name() { return myName. Console. 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.myName). Console.cs using System. } public void set_Name(string value) { myName = value. pmany[1] = new Person1("Ola".{0}".WriteLine("Person details: " + person4. Person1 person4 = new Person1("otto". Console.mySex).’m’). bool same = person2. myName.7.WriteLine("Person details .’f’). } // end Main } class Person1 defines three private member variables. // array of persons Person1[] pmany = new Person1[2]. mySex. public char mySex = ’n’.

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

person3. person2. Console. // increment the age of person3 person3.Name = "Jane".person1).Sex = ’m’.cs using System.cs contains the Main() method.WriteLine("Person details .{0}".Age).{0}". person3.{0}".WriteLine("Person details . person1.WriteLine("same person = " + same). Person person4 = new Person("otto". Console. person1.dll file we run csc /t:library Person.’m’).Age = 31. class PersonMain { public static void Main() { // create a new Person object using default constructor Person person1 = new Person().Sex = ’f’. Console.Name = "Jane". Console.WriteLine("Person details: " + person4.Name = "Joe".42.cs The file PersonMain.myName).person3). Person person3 = new Person(). Console. // PersonMain. person2. Person person2 = new Person().Age = 31.WriteLine("Person details: " + person4.Sex = ’f’.person2).WriteLine("Person details . bool same = person2. Console.Age++. // Set some values on the person object person1.Age = 99. Console.68 CHAPTER 5. .WriteLine("person3 new age: " + person3.Equals(person3). person3.mySex). person2. OBJECT-ORIENTED PROGRAMMING To generate the Person.

exe file we run csc /r:Person. An example is given below // Point3D.5.double y.cs to generate the PersonMain.cs using System. = y.double z) = x. public Point3D() { } // default constructor public { this. we can also use the short-cut csc Person. = z.Y this. .myName).WriteLine("sex of person[1]: " + pmany[1].dll PersonMain. OVERRIDE METHODS // array of persons Person[] pmany = new Person[2].23. Console.exe file.WriteLine("name of person[0]: " + pmany[0].7. public double Y. 69 5. public double Z.’m’). } // end Main } To get the PersonMain.cs However.Z } Point3D(double x.2 Override Methods bool Equals(). Console.cs PersonMain.mySex).2.’f’). object Clone() When we write our own class in most cases we should override the methods string ToString(). pmany[0] = new Person("Carl".X this. public class Point3D { public double X. pmany[1] = new Person("Ola".

5.b. OBJECT-ORIENTED PROGRAMMING // square of distance between two Points public double distance(Point3D p1.Z). 4.Z)*(p1.Y.Point3D p2) { return (p1.WriteLine("p1 = " + p1).{1}.cs using System.{2})".y. } public override string ToString() { return String. Console.X) && (Y==((Point3D) o).Y)*(p1. Point3D p1 = new Point3D(x.70 CHAPTER 5.X)*(p1.Y) && (Z==((Point3D) o).Z)) return true.Z).X. } public object Clone() { object o = new Point3D(X.1. .Y-p2. double z = 4.5. 3.Z-p2. = new Point3D(a. } } An application of this class is // Point3DMain. double y = 3.X-p2. else return false.X)+(p1.Z).X-p2. public class Point3DMain { public static void Main() { double x = 2.Y)+(p1. } public override bool Equals(object o) { if((X==((Point3D) o).Y.Z-p2. return o.1.1.1.c).Format("({0}. double a = double b = double c = Point3D p2 2.z).Y-p2.

m.Clone().0.0. First we must declare our intention to use Vehicle as the base class of Car.WriteLine("r = " + r).0).5. double k = 2. double m = 1. Point3D q = new Point3D().Equals(p2). INHERITANCE bool r = p1. Console. This is accomplished through the Car class declaration public class Car : Vehicle Then the colon. // MVehicle.n).0. Console. The class Car is derived from class Vehicle. .0. } } 71 5. In the next program we use inheritence.WriteLine("p4 = " + p4). class Vehicle { private int weight.3. Point3D p3 = new Point3D(k.WriteLine("d = " + d).distance(p1. p4 = (Point3D) p3. thus the class cannot be inherited. private int topSpeed.3 Inheritance Inheritance is one of the primary concepts of object-oriented programming. In the class Car we use code from the class Vehicle. They cannot be instantiated and may contain abstract methods and accessors. A sealed class protects against inheritence. and the keyword base call the base class constructor. Point3D p4 = new Point3D(0.cs using System. : . double n = 7. It is not possible to modify an abstract class with the sealed modifier.5.0. C# supports single class inheritance only. // type conversion Console. double d = q.p3). It allows us to reuse existing code. An abstract class can only be used as a base class of other classes.0.

int aDisplacement) : base(aWeight. } public virtual void print() { Console.WriteLine("Price: {0} Dollar". } public double getPrice() { return price. int horsepower.topSpeed). public Vehicle() {} public Vehicle(int aWeight.WriteLine("Top Speed: {0} km/h". OBJECT-ORIENTED PROGRAMMING private double price.aTopSpeed. Console. price = aPrice. } } // end class Vehicle class Car { private private private : Vehicle int numberCylinders.aPrice) { numberCylinders = aNumberCylinders.price). displacement = aDisplacement. } public int getNumberCylinders() { return numberCylinders. } public int getHorsepower() { return horsepower.int aNumberCylinders. Console. int aHorsepower. } .double aPrice) { weight = aWeight.int aTopSpeed. public Car() { } public Car(int aWeight. topSpeed = aTopSpeed.weight). int displacement. } public int getWeight() { return weight.int aTopSpeed.WriteLine("Weight: {0} kg". horsepower = aHorsepower.72 CHAPTER 5. } public int getDisplacement() { return displacement.} public int getTopSpeed() { return topSpeed.double aPrice.

indexers.30000.int period). Since interfaces must be defined by inheriting classes and structs. The reason interfaces only provide definitions is because they are inherited by classes and structs.6.12000. methods.Write("A car: ").print().print(). Console. The following program shows an example.100. The only thing it contains are definitions of events.00). } } 73 An interface looks like a class.print(). INHERITANCE public override void print() { base. they must define a contract. } } class myCar { public static void Main() { Vehicle aVehicle = new Vehicle(15000.int n) { return 7. Console.WriteLine(""). but has no implementation. which must provide an implementation for each interface member defined. aVehicle.displacement). Car aCar = new Car(3500. Console.cs public interface Policy { double Rate(double principal. // Policies. } } public class SilverPolicy : Policy . aCar. Console. Console.Write("A vehicle: "). Console.300).120. Console.120.00.WriteLine("").numberCylinders).WriteLine("Diplacement: {0} cubic cm". } public class BronzePolicy : Policy { public double Rate(double p.WriteLine("Horsepower: {0} ".horsepower).WriteLine("Cylinders: {0} ". and/or properties.5.3.

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

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

this. public double imag.7)). \. } // end main } } Exercise.1. Console.4. array[0] = 3.1.max(4. array[1] = 5.2. double max = list[0]. foreach(double val in list) { if(val > max) max = val.cs using System.4. } return max.max(3.5 Operator Overloading Operators can be overloaded (operator overloading) such that +.5 and 4.imag = imag.WriteLine("maximum of 3. 5.WriteLine("maximum element in array = {0}". 2. 4.9 is {0}". *.9.4. %. OBJECT-ORIENTED PROGRAMMING { if(list. . Console.7 is {0}". array[2] = 3.double imag) { this.4.76 CHAPTER 5. array[3] = 2.9)).Length == 0) return 0. // real part of complex number // imaginary part of number public Complex(double real.int.1.1. -. [] In the next program we overload + to add two complex numbers. // Complex. Add a method max(int. } public static void Main(string[] args) { Console. public class Complex { public double real.7.real = real.int.max(array)).WriteLine("maximum of 4.int) to the program that find the maximum of four integer numbers.5. double[] array = new double[4].

CosmicBackground = 2.real + c2. key-value pairs in a dictionary or points in a coordinate system.WriteLine("Real: {0} Imaginary: {1}i". For example.0). r1 = r1 + r2.1. Structures.imag. indexers and structors.r1. STRUCTURES AND ENUMERATIONS } public static Complex operator + (Complex c1. Enumerations are an alternative to constants when grouping related constants together. d real) is given by z1 ∗ z2 = a ∗ c − b ∗ d + i(ad + bc). } } class ComplexMain { public static void Main() { Complex r1 = new Complex(1. The objects are stored on the stack compared to classes which are stored on the heap.r1. b. return c1. Structs are useful for small data structures such as complex numbers. They should only be used for types that are small and simple. The multiplication of two complex numbers z1 = a + ib and z2 = c + id (with a.0.6.0.real. nested types. } } 77 Exercise. c. Complex r2 = new Complex(2.75. or structs.real = c1.real.0).5.imag). methods. } . Overload in the program also * for the multiplication of two complex numbers.2. contain properties.imag + c2. operators. when considering temperature we can have the following. Console. WaterBoilingPoint = 373. c1. Structs do not support inheritence or destructors. enum Temp { AbsoluteZero = 0. fields.6 Structures and Enumerations In CSharp we can also use structures.imag = c1. 5.Complex c2) { c1. WaterFreexingPoint = 273.

Age remains 13 Console. OBJECT-ORIENTED PROGRAMMING The base type for enums is integer. enum NumberChocolatesInBox :uint { SmallBox = 20. enum MemberType { Lions.a. } The program shows how structs and enumeration can be used.a.Age = 13.Name.Eagles. // a.Age.Group). MediumBox = 30. a. ClubMember b = a. } class enumeration { public static void Main(string[] args) { ClubMember a. LargeBox = 50. a. public int Age. // Value types are automatically initialized a.WriteLine("Member {0} is {1} year old and belongs to group of {2}". Dogs }. Eagles.cs using System. // enumeration. a. We can pass method m in class A.Name = "John". Elefant. } // end main } 5. // new copy of a is assigned to b b.Age = 17. wrapped in a dele- .78 CHAPTER 5. struct ClubMember { public string Name. Jackals. The following example demonstrates how to use different types.Group = MemberType. public MemberType Group.7 Delegates A delegate in C# allows us to pass methods of one class to objects of other classes that can call those methods.

NET framework as a class derived from System.cs using System.Delegate. Declare a delegate object with a signature that exactly matches the method signature that we are trying to encapsulate. Call the encapsulated methods through the delegate object. } } // end class Class1 // Step 3. Create delegate object and plug in the methods class Class2 { public MyDelegate createDelegate() { Class1 c2 = new Class1().WriteLine("delegateMethod1: the input to the method is {0}". 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. Create delegate object and plug in the methods that we want to encapsulate. Thus the use of delegates involves four steps. 1. // Step 2.input). C# delegates are implemented in the .7. // Step 1.5.WriteLine("delegateMethod2: the input to the method is {0}". 4. Define all the methods whose signature match the signature of the delegate object that we have defined in step 1. 3. The following C# program shows the above four steps. // Delegate. Define methods that match with the signature // of delegate declaration class Class1 { public void delegateMethod1(string input) { Console. We can pass both static and instance methods. Declare a delegate with the signature of the // encapsulated method public delegate void MyDelegate(string input). DELEGATES 79 gate. 2. } public void delegateMethod2(string input) { Console. .input). to class B and class B will be able to call method m in class A.

callDelegate(d. Here we use delegates to compare strings. c3. // this is the delegate declaration public delegate int Comparer(object obj1. Class3 c3 = new Class3(). MyDelegate d3 = d1 + d2.string input) { d(input).createDelegate().80 CHAPTER 5. public string LastName = null. Call the encapsulated method through the delegate class Class3 { public void callDelegate(MyDelegate d. OBJECT-ORIENTED PROGRAMMING MyDelegate d1 = new MyDelegate(c2."calling the delegate").delegateMethod1).cs using System. } // 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. } } // end class Class2 // Step 4. .object obj2). public class Name { public string FirstName = null.delegateMethod2). return d3. MyDelegate d2 = new MyDelegate(c2. // MyDelegate. MyDelegate d = c2. } } // end class Class3 class Driver { public static void Main() { Class2 c2 = new Class2().

LastName = last. names[2] = new Name("Rolf". DELEGATES public Name(string first.FirstName.object name2) { string n1 = ((Name) name1).CompareFirstNames)."Smithlone")."Xenon"). } else { return 0. } else if(string. 81 .PrintNames(). } static void Main() { SimpleDelegate sd = new SimpleDelegate(). public SimpleDelegate() { names[0] = new Name("John". sd."Cooper"). names[3] = new Name("Ola". } public static int CompareFirstNames(object name1.n2) > 0) { return 1.FirstName. // type conversion if(string. // the delegate instantiation Comparer cmp = new Comparer(Name."Jones"). names[1] = new Name("Carl".5.WriteLine("\nBefore Sort:\n"). } } // end class Name class SimpleDelegate { Name[] names = new Name[4].Compare(n1.Sort(cmp). Console.string last) { FirstName = first.n2) < 0) { return -1. // observe the delegate argument sd.Compare(n1.7. // type conversion string n2 = ((Name) name2). } } // end method CompareNames() public override string ToString() { return FirstName + " " + LastName.

Length.i++) { for(int j=i.WriteLine("\nAfter Sort:\n"). for(int i=0.WriteLine(name.j++) { // using delegate "compare" just like a normal method if(compare(names[i]. names[i] = names[j]. OBJECT-ORIENTED PROGRAMMING Console. names[j] = (Name) temp. PrintNames().Length. } } // end method PrintNames() } .82 CHAPTER 5.j<names. foreach(Name name in names) { Console. sd.names[j])>0) { temp = names[i].ToString()).WriteLine("Names:\n"). } // end if } } } // end method Sort public void PrintNames() { Console.i<names. } public void Sort(Comparer compare) { object temp.

Chapter 6 Streams and File Manipulations
6.1 Introduction

A stream is a sequence of bytes. A byte is 8 bits. The Stream class and its subclasses provide a generic view of data sources and repositories, isolating the programmer from the specific details of the operating system and underlying devices. Streams involve the following three operations: 1) Streams can be read from. Reading is the transfer of data from a stream into a data structure, such as an array of bytes. 2) Streams can be written to. Writing is the transfer of data from a data structure into a stream. 3) Streams can support seeking. Seeking is the query and modifying of the current position within a stream.

6.2

Binary File Manipulations

System.IO.BinaryWriter and System.IO.BinaryReader can be used for writing and reading primitive data types byte, short, int, long, float, double, bool, char and also the data type string and StringBuilder to a stream (binary file manipulation).

83

84 // BinaryIO1.cs using System; using System.IO; using System.Text;

CHAPTER 6. STREAMS AND FILE MANIPULATIONS

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

6.3. TEXT FILE MANIPULATION

85

class BinaryIO2 { private static void WriteData(string t,StringBuilder sb) { Stream s = File.OpenWrite("info.dat"); BinaryWriter bw = new BinaryWriter(s); // write length-prefixed string bw.Write(t); bw.Write(sb.ToString()); bw.Close(); s.Close(); } private static void ReadData() { Stream s = File.OpenRead("info.dat"); BinaryReader br = new BinaryReader(s); string t = br.ReadString(); string sb = br.ReadString(); br.Close(); s.Close(); Console.WriteLine("{0},{1}",t,sb); } public static void Main(string[] args) { StringBuilder sb = new StringBuilder("Hello World!"); WriteData("Hello Egoli",sb); ReadData(); } }

6.3

Text File Manipulation

Reading a text file. The class FileStream is useful for reading and writing files on a file system, as well as other file-related operating system handles (including pipes, standard input, standard output, and so on). FileStream buffers input and output for better performance. The FileStrean class can open a file in one of two modes, either synchronously or asynchronously, with signigicant performance consequences for the synchronous methods (FileStream.Read and FileStream.Write) and the asynchronous methods FileStream.BeginRead and FileStream.BeginWrite). Both sets of methods will work in either mode; however, the mode will affect the performance of these methods. FileStream defaults to opening files synchronously, but

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

Given the file datain.ToString("dd-MMM-yyyy").3. TEXT FILE MANIPULATION 87 string text = "all the good men and women" + "\r\n".Now. StreamWriter sw = new StreamWriter("order.cs using System. // also flushes the stream } } Writing the date and time into a file using the DateTime class.args). // placeorder. class PlaceOrder { public static void Main(string[] args) { DateTime dt = DateTime. } } The useful classes in reading/writing text files are: StreamReader and StreamWriter.true).GetBytes(text). using System..txt". // append end // of line characters byte[] buffer = Encoding. // Filemanipulation.40 Bakley 3451 2800. string record = today + "|" + String.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. sw.Close(). class FileManipulation { static void Main(string[] args) { . s.Close().Join("|".6.0.Length).ASCII.cs using System.txt.buffer.txt with the two lines Green 4750 3000.IO. sw. s. using System. string today = dt.WriteLine(record).IO.Write(buffer.

ID = int.’. using System.ReadLine().name. Console. STREAMS AND FILE MANIPULATIONS FileInfo fr = new FileInfo(@"c:\csharp\datain.Parse(substrings[1]). BufferedStream bs = new BufferedStream(s). FileShare.IO. name = substrings[0]. What happens if we remove (char) ? // BytebyByte.Parse(substrings[2]).’. float gpa. writer.Read.WriteLine("{0} {1} {2}".’\t’ }. The type conversion to char is necessary in the following program. string[] substrings. string sline.4 Byte by Byte Manipulation For reading and writing bytes we use the methods ReadByte() and WriteByte(). sline = reader.Close().cs using System.gpa).gpa).txt").WriteLine("{0} {1} {2}". while(sline != null) { substrings = sline.3). gpa = float. string name. int ID.FileAccess.Flush(). while(bs.Length > bs. writer.ReadLine(). } } 6.OpenText(). sline = reader.FileMode. } writer.ID.Position) .Open.Split(separators.txt".ID.88 CHAPTER 6. StreamReader reader = fr.Read). public class BytebyByte { public static void Main(string[] args) { FileStream s = new FileStream(args[0]. StreamWriter writer = new StreamWriter(@"c:\csharp\dataout.false).name. char[] separators = { ’ ’.

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

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

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

"Clerk".15000).ToString() } public static void Main(string[] args) { Employee emp = new Employee("Jack". class Program { // declare binary formatter to read/write serialized text from file static BinaryFormatter bf = new BinaryFormatter()."Salesman".16000).OpenRead("emp. ReadEmployee().Runtime.44000). using System. an array we extend the program binsertest1. Employee emp = (Employee) bf. static void Main(string[] args) { // declare array to hold employee objects Employee[] employees = new Employee[2].cs as follows // serialization. STREAMS AND FILE MANIPULATIONS private static void ReadEmployee() { Stream s = File. WriteEmployee(emp). s.Deserialize(s).Binary. // displays emp. // serialize employee list to file Serialize(employees).Formatters.92 CHAPTER 6. Console. // create first and second emplyee object in the array employees[0] = new Employee("John Miller". employees[1] = new Employee("Jack White".Serialization.cs using System.IO. .e. } } If we have more than one employee."Manager".bin"). // derserialize employee list DeSerialize().WriteLine(emp).Close(). i. using System.

bin").employees). bf.bin").6 XML Documents The .NET framework provides an XML parser for reading and modifying XML documents.6. XML DOCUMENTS } static void Serialize(Employee[] employees) { // serialize to file Stream stream = File. <?xml version="1.WriteLine().OpenWrite("employees.OpenRead("employees. Console. } static void DeSerialize() { Console.WriteLine().name.WriteLine(e).Deserialize(stream).WriteLine("Reading employee list from file").WriteLine("Employee list has been serialized to file"). job. Console. Console. stream. stream. There are five employees.salary) about employees.WriteLine().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> . Given below is the file emp. // loop through the array and display each employee foreach(Employee e in emps) Console.Close(). Console.Serialize(stream.xml containing information (id. Employee[] emps = (Employee[])bf. // deserialize from file Stream stream = File.6.Close(). } } 93 6.

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

CreateElement("employee").xml"). sal."").CreateNode("element".Xml. // make name tag a subtag of newly created employee tag emp. XmlNode job = doc.""). job. using System.Save("emp.xml. // save the modified document doc."salary".6. // addemp.InnerText = args[2].InnerText = args[3].CreateNode("element".SetAttribute("id". emp. // create a name tag and st its value XmlNode name = doc. name.AppendChild(sal). // add the newly created employee tag to the root (employees) tag doc. salary) and makes a new entry in the file emp.DocumentElement. job."").6.args[0]). } } We execute the program with (for example) addemp 105 willi president 50000 ."job". name.cs takes informations from the command line (id.Load("emp. class AddEmployee { public static void Main(string[] args) { XmlDocument doc = new XmlDocument().InnerText = args[1].cs using System.AppendChild(emp). XmlNode sal = doc."name".CreateNode("element". emp.AppendChild(job).AppendChild(name). // create a new employee element and value of its attribute XmlElement emp = doc.xml"). emp. XML DOCUMENTS 95 The program addemp. doc.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

9.2. THREADS t.IsBackgound = true; The thread will terminate when the application terminates. // threadtest2.cs using System; using System.Threading; // for Thread class class ThreadTest2 { public static void SayHello() { for(int i=1;;i++) { Console.WriteLine("Hello {0}",i); } } public static void Main() { Thread t = new Thread(new ThreadStart(SayHello)); t.IsBackground = true; t.Start(); for(int i=1;i<1001;i++) { Console.WriteLine("Bye {0}",i); } } }

117

9.2.3

Sleep Method

Once a thread has been started it is often useful for that thread to pause for a fixed period of time. Calling Thread.Sleep causes the thread to immediately block for a fixed number of milliseconds. The Sleep method takes as a parameter a timeout, which is the number of milliseconds that the thread should remain blocked. The Sleep method is called when a thread wants to put itself to sleep. One thread cannot call Sleep on another thread. Calling Thread.Sleep(0) causes a thread to yield the remainder of its timeslice to another thread. Calling Thread.Sleep(Timeout.Infinite) causes a thread to sleep until it is interrupted by another thread that calls Thread.Interrupt. A thread can also be paused by calling Thread.Suspend. When a thread calls Thread.Suspend on itself, the call blocks until the thread is resumed by another thread. When one thread calls Thread.Suspend on another thread, the call is a non-blocking call that causes the

118 other thread to pause.

CHAPTER 9. PROCESSES AND THREADS

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

9.2. THREADS A typical output could be Main thread: Other thread: Other thread: Main thread: Other thread: Other thread: Other thread: Main thread: Other thread: Main thread: Other thread: Other thread: Main thread: Other thread: Other thread: 0 0 1 1 2 3 4 2 5 3 6 7 4 8 9

119

At another run this could change.

9.2.4

Join Methods

The method Join() blocks the calling thread until a thread terminates. // joiningthread.cs using System; using System.Threading; class JoiningThread { public static void Run() { for(int i=1;i<3;i++) Console.WriteLine("Hello {0}",i); } public static void Main() { Thread t = new Thread(new ThreadStart(Run)); t.Start(); for(int i=1;i<6;i++) Console.WriteLine("Welcome {0}",i); t.Join(); Console.WriteLine("Goodbye"); }

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

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

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

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

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

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

for(int i=0.Increment(ref count). for(int i=0. int[] a2 = (int[]) o. Console.Length. 9.Threading.126 CHAPTER 9. using System.cs using System. allowing us to concentrate on application tasks rather than thread management. } public static void Sum2(Object o) { int sum2 = 0. i++. int[] a1 = (int[]) o. depending on our application.WriteLine("I am in ThreadJob"). An example is given below. 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.i++) . // ThreadsSum2.i<a2.i<a1. class ThreadsSum { public static void Sum1(Object o) { int sum1 = 0. } Console. Many applications use multiple threads. PROCESSES AND THREADS while(i < 5) { Interlocked.Length.WriteLine("sum1 = " + sum1).i++) { sum1 += a1[i]. 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. } } // end ThreadJob } First the for loop in Main will run to the end and then the while loop will be done.7 Thread Pooling We can use thread pooling to make much more efficient use of multiple threads.

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

128

CHAPTER 9. PROCESSES AND THREADS

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

public class Test : Form { delegate void StringParameterDelegate(string value); Label statusIndicator; Label counter; Button button; readonly object stateLock = new object();

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

129

130

CHAPTER 9. PROCESSES AND THREADS

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

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

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

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

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

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

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

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

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

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

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

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

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

TRANSMISSION CONTROL PROTOCOL The file (xml-file) Server2.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> 143 .2.10.exe.

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

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

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

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

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

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

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

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

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

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

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

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

When an application requests data a new database connection is created and destroyed when the request is completed. because of data conversion. In order to use OLEDB the following namespace must be specified.NET Framework uses ADO. ADO. A disconnected data access model is frugal with resources.NET is that information is stored and transferred in XML.Data. ADO. Note the following. which is desirable. using System. There are two basic types of connections. SQLClient is used for Microsoft’s SQL Server and OLEDB is used for all other database formats. • Choosing too large a datatype can waste space and increase capital expenses.SqlClient. One important advantage of ADO. When designing a database.Chapter 12 Accessing Databases 12.1 Introduction The . • Choosing too small a datatype cannot meet the system need and at some point your system may become useless.Data. using System. It operates on a disconnected data access model.NET is a set of managed classes within the . the correct datatypes must be chosen.NET allows access to many different databases.OleDb.NET Framework. In order to use SQL with SQL Server or SQL Server Express the following namespace must be specified.NET to access databases. 156 . • Choosing an incorect datatype can degrade performance.

this could be a SQL query or a stored procedure. The data adapter fills a DataSet object when reading the data and writes in a single batch when writing changes back to the data base. A Data Provider consists of • Connection • Command • DataReader • DataAdapter A Dataset can be understood as a virtual database table that resides in RAM. The easiest way to find the correct connection string for a DBMS is to search the Web. The Command executes an instruction against the database. For example. A DataSet can contain a set of tables with all the metadata necessary to represent the structure of the original database.12. A DataReader is used for fast and efficient forward-reading. It returns individual rows directly to the application. 1. then a DataAdapter can be used. Can return multiple rows. read-only database access. It is a middle-layer between the database (Data Provider) and the disconnected DataSet. A DataAdapter handles retrieving and updating data. 3.NET Data Provider is set up. It decouples the DataSet from the database and allows a single DataSet to represent more than one database. A Connection String is required to connect to a database. such as Delete. It can be manipulated and updated independantly of the database. 2. ExecuteNonQuery: Used for data manipulation. ExecuteScalar: Used to retrieve a value from a single field. A good site to start with is http://www. ExecuteReader: Used for accessing data. In the case that the data is read-only and rarely updated. . A DataSet is not always required. INTRODUCTION 157 Accessing a database requires that a . There are three options for executing a Command. The Connection object contains all the information needed to open the connection.com. for example the userid and password. The Connection creates the actual connection to the database. The data is not cached. Update and Insert.connectionstrings.1. In order to open and close a database connection the Connection methods Open() and Close() are used respectively. Readonly. forward-only.

WriteLine("Server Version: {0}". but providers for other databases are provided.WriteLine("Data Source: {0}". connection. Console. connection. Console. ACCESSING DATABASES An important control is the SqlDataSource. Console. SqlConnection connection = new SqlConnection(CON_STRING).Text. System. The default provider is for Microsoft SQL Server. static void Main(string[] args) { Console.WriteLine("Connecting to db\n"). connection.2 Examples The following program shows how to connect to a Microsoft SQL Server 2005 or Sql Express database and retrieve some basic information about the server. connection.DataSource). connection.WriteLine("Database: {0}". Console. namespace csDB { class OpenSQLDB { public const string CON_STRING = "Data Source=mySqlDB.Password=User1234".ServerVersion).Close(). System. Knowledge of SQL is required.SqlClient. An important concept is that of Data-Bound controls.Initial Catalog=dbTest.Data.Database). It allows connections to most relational databases. } // end Main } // end class } // end namespace .User ID=JoeUser.WriteLine("Stats Enabled: {0}". connection. They provide a link between the data source controls and the user.158 CHAPTER 12. for Oracle. System.Open().Data.StatisticsEnabled). Any data source control can be selected and linked to any data-bound controls. For example. using using using using System. Care must be taken is creating an appropriate connection string (CON STRING in these examples). 12.

user id=JoeUser.pwd=User1234. A standard SQL query is used and submitted to the database via a SqlCommand object. EXAMPLES 159 Embedding the user ID and password.NET solves this problem by using the web. it is not secure. <\configuration> The following line of code fetches the connection string from web. In the case of data retrieval the SELECT statement is used.newdb. } myReader.config file.. ASP. myReader[1] then // accesses the SECOND field.CommandText = "SELECT * FROM tblCustomer". A wildcard search can be achieved as follows. cmDB. a change in the database means the code will have to be modified and recompiled. the myReader[0] // accesses the FIRST field of data in the // the selected record.Close(). string CON_STRING=ConfigurationSettings. The assumption is that a TextBox called txtSearch is used to input the search parameters.ToString(). <configuration> <appSettings> <add key="DBConnect" value="server=mySqlDB. The basic method of retrieving data using a Data Reader is as follows. In addition.ExecuteReader(). is not a good idea.config file. cmDB.config.12.. The following is an extract from a web.2.initial catalog=dbTest. as in the above code."/> <appSettings> .Appsettings["DBConnect"]. SqlCommand cmDB = new SqlCommand().Connection = connection . . while(myReader.net. A Trim() is used to remove whitespace.Read()) { // Do something with the data // In the following code. // --------------------------------------// string strTmp = myReader[0]. SqlDataReader myReader = cmDB.ToString() + // " " + myReader[1].

" + "Initial Catalog=dbCustomer. ACCESSING DATABASES string strSearch = "SELECT * FROM tblCustomer where fldCustName LIKE ’" + TextBox1. The following code shows how to access particular fields using a Data Reader." + "Initial Catalog=dbCustomer" + ". SqlConnection connection = new SqlConnection(CON_STRING). String CON_STRING = @"Data Source=mname\sqlexpress. fltBal. connection.CommandText = strSQL.160 CHAPTER 12.ExecuteReader(). SqlConnection connection = new SqlConnection(CON_STRING). SqlCommand cmDB = new SqlCommand(). // Access SQL EXPRESS db and retrieve data and put field // values into variables string CON_STRING = "Data Source=ejd\\sqlexpress. The following code shows how to insert a row into a database.Close(). using a SQL INSERT command.Open(). string strSQL = "SELECT * FROM tblCustomer WHERE" + " fldCustSurname = ’Hardy’ AND fldCustName = ’Frank’". while (rdr.Close().Connection = connection.Text = id + " " + strName.Text.Integrated Security=True". // etc etc TextBox1.Integrated Security=True". strName = (string) rdr["fldCustName"]. int id. . // SQL uses a % for wildcard myReader = cmDB. connection.ExecuteReader().Trim() + "%’". } rdr. strSurname. float fltCred. cmDB.Read()) { id = (int) rdr["fldCustomerID"]. SqlDataReader rdr = cmDB. string strName. cmDB.

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

then it is closed if(connection.Close(). MyCmd. } finally { // The following code checks if the database is still open // If it is. connection).Message.ExecuteScalar(). String MyString = @"DELETE FROM tblCustomer " + "WHERE fldCustName = ’Greg’".Text = ex.Open(). ACCESSING DATABASES SqlConnection connection = new SqlConnection(CON_STRING). SqlCommand MyCmd = new SqlCommand(MyString. } catch (SqlException sqlexp) { // SqlException catches SQL specific exceptions // Use it when accessing SQL databases } catch (Exception ex) { TextBox1. } .State == ConnectionState.162 CHAPTER 12.Open) connection. try { connection.

The . C# is perhaps the best language to write ASP.Configuration. ASP.Data.1 Introduction ASP.Web. is essentially a standalone program.cs file requires a number of libraries to be included.Web. it follows an eight stage lifecyle.NET determines whether the page needs to be parsed and compiled (which starts the lifecycle).Web.NET Framework.aspx.UI.Chapter 13 ASP.Web.aspx. The .UI. System. System. System.Web.UI.WebControls. Web Forms have an extension of . with . and the C# code that is associated with a particular page has an extension of .NET 13. Of all the available . System.Web. 163 .NET applications. System.WebControls.NET languages. When a page is requested. Each Web page.2 Page Lifecycle When a Web Page loads. System. Page request .NET is Microsoft’s Web technology built on the . This chapter outlines some additional code that is required when programming web applications.Security. or whether a cached version of the page can be sent. These are typically as follows using using using using using using using using using System.aspx file is essentially a HTML file.WebParts.UI.aspx. System. System. 1.NET specific extentions.cs.HtmlControls. 13. or Web Form.This occurs before the page life cycle begins.

.164 CHAPTER 13.Here controls on the page are created and each control’s UniqueID property is set. Page initialization . string strTB = TextBox1. the page calls the Render method for each control. left: 0px. which is used for text input. the postback data has not yet been loaded and control property values have not been restored to the values from view state. The following code shows how to insert text into a TextBox. Validation . 6. The page’s UICulture property is also set.NET 2.View state is saved for the page and all controls before rendering is performed. TextBox1. <asp:TextBox ID="TextBox1" runat="server" Style="z-index: 100. Page properties such as Response and Request are unloaded and any cleanup is performed. Properties and Methods are typically accessed by use of the ”dot” operator.If the current request is a postback. During the rendering phase. 7. 13.1 TextBox A TextBox is used for text input.3 Controls A control is a component that is used to create GUI interfaces in ASP.This is called after the page has been rendered and sent to the client.NET and Windows development. 4. Postback event handling . 3.Text = "Hello World".Here page properties such as Request and Response are set. Load . which sets the IsValid property of individual validator controls and of the page. Themes are also applied.The Validate method of all validator controls is called. control properties are loaded with information recovered from view state and control state.Event handlers are called if the request is a postback. top: 0px"></asp:TextBox> The following code shows how to retrieve text from a TextBox. 8. 13. 5. Unload .3. If the current request is a postback. It is also determined whether the request is a postback or a new request and sets the IsPostBack property appropriately. providing a text writer that writes its output to the OutputStream of the page’s Response property. The following HTML code shows how a TextBox is typically created. position: absolute. Start . Rendering .Text. An example of a control is a TextBox. ASP.

<asp:DropDownList ID="DropDownList1" runat="server" Style="z-index: 102. <?xml version="1.Items.13.3. left: 0px. a file called Web.5 13.4 13.SelectedItem.aspx" title="Home" description=""> <siteMapNode url="default2. The following HTML code shows how a DropDownList is typically created.3.aspx" title="Contacts" description="" /> </siteMapNode> </siteMap> . string strDDL = DropDownList1. top: 0px"> </asp:DropDownList> The following code shows how to add options to a DropDownList.3.3.sitemap is required.NET for navigation. DropDownList1. DropDownList1.aspx" title="Services" description="" /> <siteMapNode url="default3.2 DropDownList A DropDownList is a similar to a TextBox.com/AspNet/SiteMap-File-1.3. CONTROLS 165 13.6 13.Items. DropDownList1.3 13. position: absolute.3.microsoft.3.Add("Joe"). Below is an example of a Web.0" encoding="utf-8" ?> <siteMap xmlns="http://schemas. 13.sitemap file.Items. except that it has predefined input options.7 CheckBox CheckBoxList RadioButton RadioButtonList Navigation When using a Menu or Treeview Controlin ASP. To retrieve the option that the user has selected.ToString().Add("Anselm"). the following code can be used.0" > <siteMapNode url="default.Add("Frank").

1. For the longer term storage of data.Expire is used to set the expiry date and time.Expires = dtNow + tsMinute. The following code retrieves the data from the Session object. Cookies are useful for storing information between visits.Value is used to store information in the cookie. 0).NavigateUrl = "default.Now. HyperLink1. Response. The HttpCookie class is used to create cookies. //Create a new cookie. TimeSpan tsMinute = new TimeSpan(0.Cookies. // Redirect to another Web Form Response. String strTmp = Request. . ASP. That leaves the problem of maintaining state between the Web Forms of a single application.QueryString["name"]. Session["sessionTmp"] = strTmp. A Query String can be created using a HyperLink control.Redirect("default2. 0.NET 13.aspx"). //Set the cookie to expire in 1 minute DateTime dtNow = DateTime.ToString(). //Set the cookies value (In this case from a DropDownList) cookie.SelectedItem. string strRetSess = Session["sessionTmp"]. Below is some code for creating cookies.Redirect("default2.aspx?name=evan". . cookie. string strTmp = "Some string". //Add the cookie Response.166 CHAPTER 13.aspx").4 State Management Web Forms can be thought of a seperate applications. .Value = DropDownList1. The code below shows how to save a variable using the Session object. passing the name into the constructor HttpCookie cookie = new HttpCookie("Names"). The Session object can achieve this. cookies can be used.Add(cookie).ToString(). The Query String can be retrieved by using the Request object.

//Check to make sure the cookie exists if (null == cookie) { Response. if(!IsPostBack) { // Code in this block will only execute once StateDropDownList.Cookies[strCookieName].ToString().Add(cookie). <br><hr>"). PAGE LOAD Data from a cookie is retrieved using the Request object. } A cookie can be deleted in the following manner. // Cookie name String strCookieName = "Names". cookie.Value.5 Page Load In the Page Load event. we employ the following code to ensure that some code is only executed the first time a Web Form is loaded. Outside of the !IsPostBack. the items will be added to the DropDownList every time the Web Form is loaded.Write("Cookie not found. StateDropDownList.Expires = DateTime. This is useful for adding items to a DropDownList. 167 13.Now.AddDays(-1).Add{"Northern Province"}.Items.Add{"Gauteng"}.Cookies.13. } .5. } else { //Write the cookie value String strCookieValue = cookie. //Grab the cookie HttpCookie cookie = Request. Response.Items.

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

63 Preprocessor Directives. 157 ExecuteScalar. 71 INSERT. 157 DateTime Class. Jagged. 7 ExecuteNonQuery. 166 SqlDataSource.NET. 159 Serialization. 167 Data Provider. 28 Bitwise operation. 157 Floating point division. 28 Boxing. 167 Cookies. 115 Thue-Morse sequence. 159 Atomic. 161 Using. 161 Dereferencing. 114 Query String. 20 Request Object. 125 binary representation. 158 Dataset. 3 Maths. One-Dimensional. 156 Array Class. 76 Pointer. 52 SELECT. 19 Polymorphism. 7 169 . 12 Operator overloading. 25 Client server model. 158 Structs. 9 Data-Bound Controls. 44 Arrays. 50 Arrays of Strings. 64 Cookies. 78 Event. 27 Arrays. 47 Type conversion. 49 ArrayList Class. 1 Sealed.Index ADO. 27 Arrays. 12 UPDATE. 52 Namespace. 157 Data Types. 78 DELETE. 73 Jagged arrays.NET. Multidimensional. 157 ExecuteReader. 48 Delegate. 26 ASP. 31 by reference. 3 Process. 19 Enumeration. 166 Scope. 137 Constructors. 77 Thread. 166 Recursion. 2 Inheritence. 90 Session Object. 7 Null character. 26 Keywords. 2 Keywords. Deleting. 110 Exception Handling. 13 Identifiers. Contextual. 13 Interface. 160 Integer division.

156 170 . 93.Worker threads. 126 XML.

Sign up to vote on this title
UsefulNot useful