C-Sharp Tutorial


Table Of Contents

Lesson 1. Hello World

Lesson 2. Classes and Class properties

Lesson 3. Command line arguments 

Lesson 4 Object-Oriented design

Lesson 5. Passing by value and by reference

Lesson 6 Understanding static and instance  members.

Lesson 7. Recursion

Lesson 8.  Exceptions

Lesson 9.  Linked List

Lesson 10. Simple Internet Programming

Lesson 11. Creating online documentation

Lesson 12.  Delegates.

Lesson 13. Events

Lesson 14. The Form, the TextBox and the CheckBox.

Lesson 15. Drawing with Pen and Brush.

Lesson 16. Numerical methods in C#.

Lesson 17. Reading a database.


Lesson 1. Hello World


The simplest C# program is of course HelloWorld: You will need C# compiler. In your favorite text editor enter the following code:

class hello
//This program does not do much
{
   public static void Main()
    {
       System.Console.WriteLine("Hello World");
    }
}

What does this code do?  Save this file as myhello.cs and type 

csc myhello.cs 

If you haven't made any typos. Something like:

Microsoft (R) Visual C# Compiler Version 7.00.9030 [CLR version 1.00.2204.21]
Copyright (C) Microsoft Corp 2000. All rights reserved.

will appear in your command prompt window. The C# compiler have created an executable code as a binary file named myhello.exe. By simply typing myhello you will see 

Hello World

What does this simple C# program look like? Java! Note that all methods (function calls) end with semicolons as in C/C++ and Java. Statements are enclosed in braces. Like Java and C/C++ every program has a Main() entry point. However in Java the name of the program should be the same as the name of the class. There is no such restriction in C#. System.Console outputs Hello World  into the console window. Other methods of System.Console include Write method which does not add carriage return at the end of the line and ReadLine which gets user input from the console.


Lesson 2. Classes and Class properties


Here is a simple program that introduces C# classes.

using System;
public class myFirst
{
    private int data=987;
    public int show_data()
    {
       return data;
    }
};

class Test
{
    public static void Main()
    {
       myFirst example = new myFirst();
       Console.WriteLine(example.show_data();
    }
}

The fist statement of the program  using System; is a declaration of namespace System which takes care of input and output. The class declaration public class myFirst  should be familiar to C++ and Java programmers. If you are a C programmer than you can think of a class as of structure with some additional capabilities which I will discuss later. Class myFirst  has a private data member int data which is initialized to 987 and method show_data() which returns the value of data.

Class Test.

Inside class Test  we create an object  example of type myFirst  and call show_data()  to show value of data. The later is then printed on the screen with help of Console.WriteLine. Let us rewrite the myFirst   class as follows:

public class myFirst
{
    private int data=987;
    public int show_data
    {
    get {return data;}
    }
};

Have you noticed a slight change in show_data? The parentheses are gone and return statement is put inside get  in braces. show_data  is now a property of class myFirst  and get  is an accessor of property show_data. get  accessor has a twin set which is used to for setting a value of a property.

 


Lesson 3. Command line arguments 


The program below shows how command line input is achieved in C#

using System;

class myName
{
    public static void Main (string[] argument )
{
    string name;
    int num_char;
    if( argument.Length != 1)
   {
       Console.WriteLine( "Only one argument is allowed");
        return;
   }
    else
    {
       name=argument[0];
       num_char=name.Length;
       Console.WriteLine("Hello {0}! The number of characters in your name is {1}.",
            name, num_char);
    }
}

You may have noticed that Main is declared to accept a string array argument as an argument.We are assuming that only one argument is passed on the command line. It means that string array argument consists of a single member which is its first element argument[0]  So if your compiled code is in a file myname.exe and you type: 

myname John

John is copied from argument[0] to name. The number of characters in name is found with the help of a built in method Length; and the result is stored in num_char . Perhaps the other thing, worth mentioning in this program, is a simple error checking mechanism. Imagine that we have mistakenly typed 

myname John Wine

the number of elements  in the array  argument is 2. Then argument.Length != 1  and an error message is printed on the screen. Try modifying this program so that it accepts an arbitrary number of arguments and prints them with the number of characters in each of them. Good Luck.

 


Lesson 4 Object-Oriented design


Object oriented programming is not a science but an art. Programming is a hard, time consuming work with no perfect solutions. Widespread use of personal computers have generated a demand for more and more complex applications  which contain hundreds of thousands of lines of code. This code needs to be updated, adjusted and debugged these tasks often take as much time as would have been spent rewriting the application from scratch. Productivity of a single programmer is very low compared to a worker of another profession. While a milkman can milk dozens of cows during his workday and a doctor can take care of dozens of patients. An average programmer may write 100 or so lines of code which constitute .1% of any useful application. So to simplify and expedite software development newer languages are developed to simplify and facilitate the tasks of the software developer. Object oriented design is an attempt in this direction. In a few years something else will take its place, but today it is the best ad hoc set of rules that each programmer strives to follow in her/his work. The idea of object oriented programming is very simple: Structure your program in logical units. These units are  called objects but the name sometimes sound more complicated than what it describes. The elements of object oriented design are

Inheritance:  Let a more specialized object  inherit from a more general object.

using System;
class Demo
{
   public class animal
   {
      int weight;
      string name;
      public void show()
      {
         Console.WriteLine ("{0} has weight {1}", name, weight);
      }
      public void my_set (int k, string z)
      {
         weight=k;
         name=z;
      }
   }
   public class tiger:animal
   {
      public tiger()
      {
         my_set(100,"tiger");
         show();
      }
   }
   public class
lion:animal
   {
      public lion()
      {
         my_set(200,"lion");
         show();
      }
   }
    public static void Main()
   {
      tiger Mike = new tiger();
      lion Bob = new lion();
   }
}

In the program above, classes  lion: and  tiger are derived from class animal.  Class animal  is called base class. Derivation is considered a good idea if a derived class satisfies "is a " relationship with respect to the base class.In our case tiger and lion are animals, so this relationship is satisfied.

Polymorphism: Use the same object to  perform  some logical task under different circumstances

Encapsulation: Try to give objects not more control to other objects than necessary.

Try to give simple examples of Inheritance, Polymorphism and Encapsulation in C#. Good Luck!

 


Lesson 5. Passing by value and by reference


Here is a simple program that attempts to modify an integer.

using System;
//does not change value of k
class Demo
{
   public class Test
   {
       public void change (int k)
       {
       k=k+2;
       }
   }
   public static void Main()
   {
      int i=3;
      Test hi=new Test();
      Console.WriteLine("Before {0} ", i);
      hi.change(i);
      Console.WriteLine("After {0} ", i);
   }
}

If you compile and execute this program you will find that the value of the integer have not been changed by method change. The reason is quite simple: method change takes a value of i, makes a copy of it, adds 2 to the copy and returns control to the main. Value of i does not change.When  change returns, its local copy of variable i disappears ( goes out of scope). When  Console.WriteLine("After {0} ",i); is called, it uses i which was never changed. A simple fix is to modify method change so that it returns a value:

using System;
// Circumvent the problem of changing value of i.
class Demo
{
    public class Test{
        public int change (int k)
        {
        return k+2;
        }
    }
    public static void Main()
    {
    int i=3;
    Test hi=new Test();
    Console.WriteLine("Before {0} ",i);
    Console.WriteLine("After {0} ", hi.change(i));
    }
}

The code above works fines but it does not change the value of i. To change we need to pass it by reference. When passing by reference compiler changes instead of changing a local copy. To do this we need to add keyword ref  indicating that change takes a reference as an argument.

using System;
class Demo
{
   public class Test{
      public void change(ref int k)
      {
         k=k+2;
      }
   }
   public static void Main()
   {
      int i=3;
      Test hi=new Test();
      Console.WriteLine("Before {0} ", i);
      hi.change(ref  i);
      Console.WriteLine("After {0} ", i);
   }
}

The output of this program is:

Before 3
After 5


Lesson 6 Understanding static and instance  members.


Static member of a class is shared by all instances of the class. Here is a simple example:

using System;
class Demo{
    public static int k;
    public int i;
    public void show(){
        Console.WriteLine("k={0} i={1}", k, i);
    }    
}
class Test{
public static void Main(){
    Demo a = new Demo();
    a.i = 1;
    Demo b = new Demo();
    b.i = 2;
    Demo.k = 4;
    a.show();
    b.show();
    }    
}

Output:

k=4 j=1
k=4 j=2

Class Demo has a static member k and an instance member i. Class Test has two objects of type Demo: a and b. Since k is static 

Instance variable i can have different values for different objects.

The second property is especially important. The compiler allocates static and non static objects with different addressing schemes and one has to be careful that no references are passed between static and non static members. Here is a simple example:

using System;
public class Test{
   public static void swap (ref int x, ref int y)
   {
      int temp=x;
      x = y;
      y = temp;
   }
   static void Main()
   {
      int a = 2;
      int b = 4;
      swap(ref a, ref b);
      Console.WriteLine("a={0}, b={1}",a,b);
   }
}

Main and swap are two static methods of class Test and they can pass references to each other. Alternatively you could pass a reference to an object:

using System;
public class Swap{
   public void swap (ref int x, ref int y)
   {
      int temp=x;
      x=y;
      y=temp;
   }
}
public class Test
{
   static void Main()
   {
      int a=2;
      int b=4;
      Swap hi = new Swap();
      
      hi.swap(ref a, ref b);
      Console.WriteLine ("a={0}, b={1}", a, b);
   }
}

I haven't discussed static members of methods. Could you come up with a simple example?

 

Lesson 7. Recursion


Here is a simple recursive program that prints a decimal integer.

using System;
class Print
{
   public void print (int n)
   {
      if(n>=10)
      print(n/10);
      Console.Write (n%10);
   }
}
class Demo
{
   public static void Main()
   {
      Print test = new Print();
      test.print (31);
   }
}

I have used 31 as an input, but any other number would certainly work. How does print work? First it checks that 31 is bigger than 10 and calls print(3). Since 3 is less than 10, 3 is printed on the console. Control is returned to 31, and  since 31%10=1 is 1, it is printed on the console. Since Write has no carriage return, 3 and 1 are printed side by side as 31. Here is a much more interesting recursive program, which generates all possible permutations of  an array t;

using System;
class Perm{
   public void swap (ref int a, ref int b)
   {
      int temp = a;
      a = b;
      b = temp;
   }
   public void perm (int []list, int k, int m)
   {
      int i;
      if (k == m){ 
         for (i = 0; i <= m; i++)
         Console.Write (list [i]);
         Console.WriteLine (" ");
      }
      else
         for (i = k; i <= m; i++)
         {
            swap (ref list [k], ref list [i]);
            perm (list, k+1, m);
            swap (ref list [k], ref list [i]);
         }
   }
}
class Demo{
   public static void Main()
   {
      Perm test = new Perm();
      int [] t={1, 2, 3};
      test.perm(t, 0, 2);
   }
}

Output:

123
132
213
231
321
312

Note the declaration of  integer array t : int []t  is inverse to that in C++.

 

Lesson 8.  Exceptions


There are no exceptions in C and in C++ one can get away from using them with error handling functions such as exit() and terminate(). In C# these functions are absent and we introduce exceptions which take their place.  When a program has a bug we can intercept it in the flow of execution by inserting an error handling statement. For example let's say we have a program which does not accesses the first element of an array. Then, during some array handling operations, if an access to array[0] is attempted, the OutOfRange exception is thrown. class OutOfRange  is an exception class. All exception classes inherit from class. Compiler will give an error if the inheritance from the Exception class is not made. In the code that follows we throw an exception OutOfRange if i == 0 is true. The try statement is enclosing the part of the code where the exception is expected. If the exception occurs it is handled by the code inside the catch statement. The catch statement  takes as an argument an instance of class System.Exception.

//first exception handling program
using System;
class OutOfRange: Exception{
}
 
class Demo
{
    int n;
    public int []array;
    public Demo ( int n)
    {
        this.array = new int[n];
        this.n = n;
    }
 
    public void show_element (int i)
    {
        try
        {
            if (i == 0) throw ( new OutOfRange());
        }
        catch (Exception e)
        {
            Console.WriteLine("Exception : {0}", e);
        }
 
        Console.WriteLine (array [i]);
    }
}
class Test
{
    public static void Main()
    {
        Demo test = new  Demo (3);
        test.array [1] = 2;
        test.array [2] = 3;
        test.show_element (0);
    }
}

The output is :

Exception : OutOfRange: An exception of type OutOfRange was thrown. at Demo.show_element(Int32 i) in G:\CSharpEd\excep.cs:line 19
0

The previous program can be simplified if you use a built in Exception class provided by the C# runtime. The full list of built in Exception classes hasn't been published yet by Microsoft at the time of this writing.

OutOfMemoryException Thrown when an allocation of  memory  fails.
StackOverflowException Infinite recursion.
IndexOutOfRangeException Out of bounds access to an array
ArithmeticException A base class for exceptions DivideByZeroException and OverflowException
OverflowException Overlflow
DivideByZeroException Division by zero

In the following program I use built in ArgumentException instead of OutOfRange exception.

//a better way to handle an Argument exception
using System;
class Demo
{
    int n;
    public int []array;
    public Demo (int n)
    {
        this .array = new int [n];
        this .n = n;
    }
    public void show_element (int i)
    {
        try
        {
            if (i == 0) throw new ArgumentException ("Out of rannge");
        }
        catch (ArgumentException e)
        {
            Console.WriteLine("Exception : {0}", e);
            return ;
        }
        Console.WriteLine (array [i]);
    }
}
class Test
{
    public static void Main()
    {
        Demo test = new Demo(3);
        test.array [1] = 2;
        test.array [2] = 3;
        test.show_element (0);
    }
}

Write a simple program which divides two integers and try using DivideByZeroException exception. Good Luck!

 

Lesson 9.  Linked List


We have learned enough C# machinery to write a simple data structure - linked list. Linked lists are used to save memory at a loss of speed. The are many different implementations of linked lists. The one bellow has a head node and a tail node. These are dummy nodes which point to the first and last elements of the list respectively. List is empty when the head node points to the tail node. The tailnode points to itself.

using System;
class OutOfRange: Exception{}
class ListNode
{
    public int data;
    public ListNode next;
};
class List
{
    ListNode headnode, tailnode;
    //list constructor initializes headnode with 0 and makes it point to the tail marker
    //headnode and tailnode do not contain any actual elements; tailnode always points to itself
    public List ()
    {
        headnode = new ListNode (); // List constructor allocates memory for headnode and tailnode
        headnode.data = 0;
        //and does the initialization
        tailnode = new ListNode ();
        tailnode.data = 0;
        headnode.next = tailnode;
        tailnode.next = tailnode;
    }
 
    // *move_to_node returns pointer to the kth element in the linked list or error if list
    //has less than k elements; headnode and tailnode are not counted as elements of the list
    public ListNode move_to_node (int k)
    {
        int i;
        ListNode temp = headnode;
        for (i = 0; i < k && temp != tailnode; i++)
        {
            temp = temp.next;
        }
        try {
            if (i < k)
                throw (new OutOfRange() );
        }
        catch (Exception e)
        {
            Console.WriteLine("Exception :{}", e);
        }
        return temp;
    }
 
    //insert node a_node after position k.headnode has 0s position;
    public void insert_node (ListNode a_node, int position)
    {
        a_node.next = move_to_node(position).next;
        move_to_node(position).next = a_node;
     }
     //delete node at position and reclaim its memory
 
    public void delete_node (int position)
    {
        //check that a_node is not a headnode or a tailnode; exit if it is
         try
        {
            if (position == 0 || position > list_length ()) // Headnode or tailnode cannot be deleted
                 throw (new OutOfRange());
        }
        catch (Exception e)
        {
             Console.WriteLine("Exception :{}", e);
        }
 
        ListNode temp;
        temp = move_to_node (position);
        move_to_node (position - 1).next = move_to_node (position + 1);
    }
    //return # of elements in the linked list excluding headnode and tailnode
    public int list_length()
    {
        int i;
        ListNode temp = headnode;
        for (i = 0; temp != tailnode; i++)
        {
            temp = temp.next;
         }
        return i - 1;
    }
    //return 1 position of integer k in list of length n
    int search(int k, int n)
    {
        try {
            if (list_length () > 0) // this assertion cheks that list exist
                 throw (new OutOfRange() );
        }
        catch (Exception e)
        {
            Console.WriteLine ("Exception :{}", e);
        }
        ListNode temp = headnode;
        temp = headnode.next;
        // move along the list till integer k is found or tailnode encountered
        for (; temp.data != k && temp != tailnode; temp = temp.next)
            ;
        if (temp == tailnode)
        {
            // k is not in the list
            return 0;
        }
        else {
            // k is in the list;
            return 1;
        }
    }
    public void show_list()
    {
        ListNode temp = headnode;
        temp = headnode.next;
        for (; temp != tailnode; temp = temp.next)
            Console.WriteLine (temp.data);
    }
};
 
class Test{
    public static void Main ()
    {
        List first_list = new List ();
        ListNode node = new ListNode ();
        node.data = 1;
        first_list.insert_node (node, 0); // insert first node into list
        for (int i = 2; i < 11; i++) { // insert 9 more nodes
            node = new ListNode ();
            node.data = i;
            first_list.insert_node (node, 0);
        }
        first_list.show_list (); //show contents of the list
    }
}

Note how similar above implementation of the linked list to ones we have in C++. Just get rid of pointers, delete statements change cout to Console.WriteLine and you are ready to go.

 

Lesson 10. Simple Internet Programming


The internet programming is very complex. There are many different conflicting protocols and the older technology conflicts with  a newer one. The idea of .Net is to make the internet more streamlined. Streamlining requires a uniform standard of web publishing. This standard would require web sites (servers) to provide extensive services for the users (clients). The internet then would become something like a huge operating system. I think that Microsoft has a very good idea and that the development of .Net will make the Internet more functional. However, I would like to separate technical issues from PR campaign since the latter tend to get out of control. The time will show whether or not Microsoft will succeed in making the Internet a better (and more profitable for Microsoft) place. We will write two programs. Both of these programs need to be compiled with  

r:System.Net.dll 

option. I will start with a simple program that translates Domain Name into IP address. System.Net namespace is an interface for internet protocols which are currently supported by .Net. System.Net contains classes DNS, IPAddress, IPHostEntry. Let me start with class DNS. It provides simple domain name resolution. Some of DNS 's methods are:

GetHostByAddr(hostname_string ) Creates an IPHostEntry instance from an IP dotted address. For example hostname_string=111.222.32
GetHostByName(hostname_string) Retrieves the IPHostEntry information corresponding to the Domain name provided in the host parameter.
GetHostName(void ) Gets the host name of the local machine.
InetAddr(ip_address_string) Converts an IP address string to an IPAddress instance.
Resolve(hostname_string) Translates a hostname to an IPAddress instance.

The program uses method DNS.GetHostByName to create an IPHostEntry.  

Methods of IPAddress has not yet been published by Microsoft at the time of this writing. For the purposes of this lesson we will  treat IPHostEntry as a black box.

using System;
using System.Net;
class IP
{
    IPAddress [] address;
    public void resolve (string host )
   {
      IPHostEntry entry = DNS.GetHostByName (host);
      address = entry.AddressList;
   }
    public void show_address()
   {
       for( int i = 0; i < address.Length; i++)
      Console.Write (address [i]);
   }
}
class Test
{
   public static void Main()
   {
      IP test = new IP ();
      string input = Console.ReadLine ();
      test.resolve (input);
      test.show_address ();
   }
}

Here is another simple program. The program treats a web page as a string of text and reads it character by character until it encounters the end of page marker. Domain names need to be provided on command line in a complete form. For example to access ABC you would type http://www.abc.com/. The WebRequest and WebResponse are base classes  used to acces data from the Internet.  The C# application works with instances of the WebRequest and WebResponse. The details of the request/response interaction  are carried out by protocol-specific descendent classes. WebRequest.GetResponse() returns the response to the Internet request. WebRequestFactory creates WebRequestobjects for specific network request schemes. The  program bellow also  illustrates usage of Input/Output library provided by System.Net namespace

using System;
using System.Net;
using System.IO;
public class Test
{
   public static void Main ()
   {
      string url_string = Console.ReadLine ();

      //make WebRequest to abc's URL
      WebRequest myRequest = WebRequestFactory.Create (url_string);

      //store the response in myResponse
      WebResponse myResponse = myRequest.GetResponse();

      //register I/O stream associated with myResponse
      Stream myStream = myResponse.GetResponseStream ();

      //create StreamReader that reads characters one at a time
      StreamReader myReader = new StreamReader (myStream);

      string s = myReader.ReadToEnd ();
      Console.WriteLine (s); //keep reading till the end of the stream
   }
}

There is absolutely no error checking in this program. I have left out exception handling for two reasons. First, to keep the program as simple as possible. Second, to illustrate huge differences between implementations of different websites. Web sites like http://xxx.lanl.gov deny this type of access. While http://www.cbs.com generates a large number of (JavaScript?) errors.

 

Lesson 11. Creating online documentation


C# allows automatic generation of comments in XML format. XML is similar to HTML and I will discuss it later in more details. For now lets concentrate on C#. Note that all programs in this lessons need to be compiled with the option /doc. For example if you save the program below in a file hello.cs and want to generate hello.xml you would type csc /doc:hello.xml hello.cs .To generate an XML file from a C# program we add triple slash comments /// . The simplest comment starts with a keyword  <summary>  and ends with a keyword <\summary> . Comments should be placed just before the line of code they are annotating.

//This is just a comment
using System;
///<summary> class Test has only one method </summary>
class Test
{
    ///<summary> string z contains identifier to output </summary>
    private static string z="Hello";
    ///<summary> method Main is an entry point of the program </summary>
    public static void Main()
    {
    Console.WriteLine(z);
    }
}

Let's look inside hello.xml. which captures the general structure of the program  hello.cs  Here is a small dictionary

T Type. Class Test is a type.
F Class member. z is a data member of class Test.
M Method. Main is a method of class Test.
! Error. Dead link.
P Property.

  <?xml version="1.0" ?>
- <doc>
- <assembly>
  <name>comment</name>
  </assembly>
- <members>
- <member name="T:Test">
  <summary>class Test has only one method</summary>
  </member>
- <member name="F:Test.z">
  <summary>string z contains identifier to output</summary>
  </member>
- <member name="M:Test.Main">
  <summary>method Main is an entry point of the program</summary>
  </member>
  </members>
  </doc>

Other interesting commands are:

There are also other elements which I will explain in more detail after I write an introduction to XML.

 

Lesson 12.  Delegates.


Let's consider a problem of calculating a numerical integral. We would like to have a method which takes different functions and outputs corresponding values of the integral of these functions. In C++ the code would look like this:
#include<iostream>
using namespace std;

//calculate the integral of f(x) between x=a and x=b by splitting the interval in step_number steps
double integral(double (*f)(double x),double a, double b,int step_number)
{
    double sum=0;
    double step_size=(b-a)/step_number;
    for(int i=1;i<=step_number;i++)
    sum=sum+f(a+i*step_size)*step_size; //divide the area under f(x) into step_number rectangles and sum their areas 
    return sum;
}
//simple functions to be integrated 
double f1( double x)
{
    return x*x;
}
double f2(double x)
{
    return x*x*x;
}
void main()
{//output the value of the integral.
    cout<<integral(f1,1,10,20)<<endl;
}
How would we do the same thing in C#? The code bellow is almost exactly the same. The main difference is that method integral takes a delegate instead of a pointer to a function. An instance of a delegate new Integral.Function(f1) must be passed to the method integral.

using System;
//calculate the integral of f(x) between x=a and x=b by splitting the interval in step_number steps
class Integral
{
    public delegate double Function(double x); //declare a delegate that takes a     double and returns a double
    public static double integral(Function f,double a, double b,int step_number)
    {
      
  double sum=0;
          double step_size=(b-a)/step_number;
         for(int
i=1;i<=step_number;i++)
        sum=sum+f(a+i*step_size)*step_size; //divide the area under f(x) into            step_number rectangles and sum their areas
          return sum;
    }
}
class Test
{
    //simple functions to be integrated
    public static double f1( double x)
{
    return x*x;
}
public static double f2(double x)
{
    return x*x*x;
}
public static void Main()
{//output the value of the integral.
    Console.WriteLine(Integral.integral(new Integral.Function(f1),1,10,20));
}
}


Lesson 13. Events


Let's start with a simple event algorithm.
Data: John is a 3rd grade student.
Event: John gets a grade (A-F)
Who is affected?: Mom, dad, sister.
How are they affected?: Mom and dad are happy when the grade is good (better than C) and upset otherwise. 
Since John and his sister just had a fight, John's sister has an opposite reaction to her parents'. Bellow is a simple program which illustrates John's family reaction to his grades. Class Test is listening to all events of type grade. Every time a new grade is received, class Test triggers an event. Class Event sends a message to a class that is subscribed to the event. If no class is subscribed, the event is not handled by the program.

using System;
public delegate void grade_event(string s);

class Event
{
    public event grade_event grade;//delegate grade is a member of Event

    public void trigger_event(string s)
    {
    if(grade!=null)
        grade(s);
    else Console.WriteLine("Event is not registered");
    }
}
class Test
{
    public static void catch_event(string s)
    {
        Console.WriteLine(" Grade event "+s+" is caught");
         if(s=="A"||s=="B"){
            Console.WriteLine("The mom and the Dad are happy with "+s);
            Console.WriteLine(" The sister is upset with "+s);
        }
         else if( s=="C" || s=="D" || s=="F"){
            Console.WriteLine(" The mom and the dad are upset with "+s);
            Console.WriteLine(" The sister is happy with "+s);
        }
         else
        Console.WriteLine("The mom, the dad and the sister cannot understand teacher's handwriting");
    }

    public static void Main()
    {
        Event my_event=new Event();
        my_event.grade+=new grade_event(catch_event); //register grade with catch_event
        my_event.trigger_event("A");
        my_event.trigger_event("B");
        my_event.trigger_event("abrakadabra");
        my_event.grade-=new grade_event(catch_event); //quit registration
        }
}

Several different classes can use the same event handler to subscribe to messages. Here is another program which illustrates this point. This program has a class Grade which sends messages about John's grades and class Health which sends messages about his health.

using System;
public delegate void my_event(string s);

class Event
{
    public event my_event mevent;//delegate mevent is a member of Event
    public void trigger_event(string s)
    {
    if(mevent!=null)
        mevent(s);
    else Console.WriteLine("Event is not registered");
    }
}
class Grade
{
    public static void catch_event(string s)
    {
        Console.WriteLine("Grade event "+s+" is caught");
        if(s=="A"||s=="B"){
            Console.WriteLine("Mam and Dad are happy with "+s);
            Console.WriteLine("Sister is uppset with "+s);
        }
         else if(s=="C"||s=="D"||s=="F"){
            Console.WriteLine("Mam and Dad are uppset with "+s);
            Console.WriteLine("Sister is happy with "+s);
        }
         else
        Console.WriteLine("Mam, Dad and sister cannot understand teacher's handwriting");
    }

    public Grade()
    {
        Event test=new Event();
        test.mevent+=new my_event(catch_event); //register grade with catch_event
        test.trigger_event("A");
        test.trigger_event("B");
        test.trigger_event("abrakadabra");
        test.mevent-=new my_event(catch_event); //quit registration
       }
}

class Health
{
    public static void catch_event(string s)
    {
        Console.WriteLine("Health event "+s+" is caught");
         if(s=="sick"||s=="ill"){
            Console.WriteLine("Mam and Dad and the sister are worried that John is"+s);
        }
    }
    public Health()
    {
        Event test=new Event();
        test.mevent+=new my_event(catch_event); //register grade with catch_event
        test.trigger_event("sick");
        test.trigger_event("ill");
        test.trigger_event("abrakadabra");
        test.mevent-=new my_event(catch_event); //quit registration
    }
}

public class Test
{
    public static void Main()
    {
    Health t1=new Health();
    Grade t2=new Grade();
    }
}
We will see in the next lesson how events are handled by the Graphical User Interface.


Lesson 14. The Form, the TextBox and the CheckBox.


The WinForms namespace has a lot of very interesting classes. One of the simplest is the Form class. Note that all programs in this lesson need to be compiled with the option /r:System.dll  /r:System.WinForms.dll /r:System.Drawing.dll  /r:Microsoft.Win32.Interop.dll. The code bellow displays a gray form untitled "How do you do?".

//A very simple form
using System.WinForms;
class test:Form //class test inherit from the class Form
{
    public static void Main()
    {
    test HelloForm=new test(); 
    HelloForm.Text="How do you do?";//specify title of the form
    Application.Run(HelloForm);//display form
    }
}

Below I create a Form containing a TextBox. Note, that the TextBox and the Form are created separately and then attached to each other  with Controls.Add. 

//A very simple form with attached textbox
using System.WinForms;
class test:Form //class test inherit from the class Form
{
    public static void Main()
    {
    test HelloForm=new test(); //create form
    System.WinForms.TextBox text=new System.WinForms.TextBox(); //create textbox

    text.Text="This is a textbox";// Specify default text to be displayed inside TextBox
    HelloForm.Controls.Add(text);//Attach TextBox to the Form
    Application.Run(HelloForm);//display form
    }
}

Bellow is a program which creates a simple CheckBox. I have changed the form's background color  with BackColor.

//A very simple checkbox
using System.WinForms;

class test:Form //class test inherit from the class Form
{
    public static void Main()
    {
    test HelloForm=new test(); 
    HelloForm.BackColor=System.Drawing.Color.Yellow; //set the color of the form

    System.WinForms.CheckBox check=new System.WinForms.CheckBox();

    HelloForm.Controls.Add(check);//Attach CheckBox to the Form
    Application.Run(HelloForm);//display form
    }
}


We will explorer other interesting classes belonging to WinForms namespace in the next lesson. In the meantime, try creating barebones applications using RadionButton and ListBox. Good Luck!


Lesson 15. Drawing with Pen and Brush.


In this lesson I would like to introduce the Pen  and the Brush objects. The following code draws a blue line intersecting a red ellipse. The code is pretty straightforward, once you override the OnPaint member of Form class. An instance of Graphics object g is then created. The area of the form where the drawing takes place is designated. This area is called ClientRectangle and by default is the whole area of the Form. The rest of the program is fairly easy. I specify two points the ClientRectangle between which I draw a line. Note that I have also created a pen to  draw this line in blue. To draw an ellipse, an invisible rectangle needs to be specified in the ClientRectangle. Then the ellipse is inscribed inside this rectangle. To change the shape and the position of ellipse you will need to change the shape and the position of the rectangle in which it is inscribed. 

class Test:System.WinForms.Form
{
    //in order to paint something OnPaint method needs to be overridden
    protected override void OnPaint(System.WinForms.PaintEventArgs pe)
    {
    //OnPaint method is a member of Form class 
    //The following call sends pe to an event listener Graphics
    base.OnPaint(pe);
    //initialize Graphics 
    System.Drawing.Graphics g=pe.Graphics;
    //designate the area of the form where the drawing must take place
    //ClientRectangle is a member of WinForms.Control class
    System.Drawing.Rectangle client_area=this.ClientRectangle;
    //point11 is at the top left corner of the client_area
    System.Drawing.Point point11=new System.Drawing.Point(client_area.X,client_area.Y); 
    //point12 is at the bottom right corner of the client area
    System.Drawing.Point point12=new System.Drawing.Point(client_area.Width,client_area.Height);
    //create a Brush object of white color
    //SolidBrush means that the color does not change from point to point
    System.Drawing.Brush background=new System.Drawing.SolidBrush(System.Drawing.Color.White);
    //color client_area with solid white brush
    g.FillRectangle(background,client_area);
    //make red and blue pens
    System.Drawing.Pen p=new System.Drawing.Pen(System.Drawing.Color.Red);
    System.Drawing.Pen p1=new System.Drawing.Pen(System.Drawing.Color.Blue);
    //create points and rectangles
    System.Drawing.SizeF size=new System.Drawing.SizeF();
    size.Height=160;
    size. Width=180;
    System.Drawing.PointF point=new System.Drawing.PointF();
    point.X=8;
    point.Y=40;
    System.Drawing.Point point1=new System.Drawing.Point();
    point1.X=300;
    point1.Y=300;
    System.Drawing.Point point2=new System.Drawing.Point();
    point2.X=0;
    point2.Y=0;
    System.Drawing.RectangleF rec =new System.Drawing.RectangleF(point,size);
    //draw an ellipse inscribed in the invisible rectangle rec
    //to change the size or shape of the ellipse change an invisible rectangle in which it is inscribed
    //to change the color of the ellipse, change the color of the pen p which is used to draw it
    g.DrawEllipse(p,rec);
    //draw a line between a pair of points point1 and point2 with pen p1
    g.DrawLine(p1,point1,point2);
    }
    public static void Main()
    {
    System.WinForms.Application.Run(new Test());//display form
    }
}

There are many other very interesting figures and shapes you could draw with Pen and Brush. It is a lot of fun! Write to me if you would like to share your work or your ideas with other readers. Good Luck!


Lesson 16. Numerical methods in C#.


In this lesson I will show how to numerically solve algebraic  and ordinary differential equations, and perform numerical integration with Simpson method. I will start with the solution of algebraic equations. The secant method is one of the simplest methods for solving algebraic equations. It is usually used as a part of a larger algorithm to improve convergence. As in any numerical algorithm, we need to check that the method is converging to a given precision in a certain number of steps. This is a precaution to avoid an infinite loop.

//secant method
using System;
class Secant
{
    public delegate double Function(double x); //declare a delegate that takes double and returns double

    public static void secant(int step_number, double point1,double point2,Function f)
    {
        double p2,p1,p0,prec=.0001f; //set precision to .0001
        int i;
        p0=f(point1);
        p1=f(point2);
        p2=p1-f(p1)*(p1-p0)/(f(p1)-f(p0)); //secant formula

        for(i=0;System.Math.Abs(p2)>prec &&i<step_number;i++) //iterate till precision goal is not met or the maximum //number of steps is reached
        {
            p0=p1;
            p1=p2;
            p2=p1-f(p1)*(p1-p0)/(f(p1)-f(p0));
        }
        if(i<step_number)
            Console.WriteLine(p2); //method converges
        else
            Console.WriteLine("{0}.The method did not converge",p2);//method does not converge
    }
}
class Demo
{//equation f1(x)==0;
    public static double f1( double x)
    {
        return x*x*x-2*x-5;
    }

    public static void Main()
    {

    Secant.secant(5,0,1,new Secant.Function(f1));
    }
}

Our second example is a Simpson integration algorithm. We have introduced numerical integration in our discussion of delegates in Lesson12. The Simpson algorithm is more precise the naive integration algorithm I have used there. The basic idea of the Simpson algorithm is to sample the integrand in a number of points to get a better estimate of its variations in a given interval. So Simpson method is more precise than the method shown in Lesson12, however since Simpson method samples more points it is slower.

//Simpson integration algorithm
using System;
//calculate the integral of f(x) between x=a and x=b by spliting the interval in step_number steps
class Integral
{
    public delegate double Function(double x); //declare a delegate that takes and returns double 
    public static double integral(Function f,double a, double b,int step_number)
    {
          double sum=0;
          double step_size=(b-a)/step_number;
         for(int i=0;i<step_number;i=i+2) //Simpson algorithm samples the integrand in several point which significantly improves //precision.
        sum=sum+(f(a+i*step_size)+4*f(a+(i+1)*step_size)+f(a+(i+2)*step_size))*step_size/3; //divide the area under f(x)     //into step_number rectangles and sum their areas 
          return sum;
    }
}

class Test
{
    //simple functions to be integrated 
    public static double f1( double x)
    {
    return x*x;
    }

    public static double f2(double x)
    {
    return x*x*x;
    }

    public static void Main()
    {//output the value of the integral.
    Console.WriteLine(Integral.integral(new Integral.Function(f1),1,10,20));
    }
}

Finally, let me show a simple code for solving first order ordinary differential equations. The code uses a Runge-Kutta method. The simplest method to solve ODE is to do a Taylor expansion, which is called Euler's method. Euler's method approximates the solution with the series of consecutive secants. The error in Euler's method is O(h) on every step of size h. The Runge-Kutta method has an error O(h^4)

using System;
//fourth order Runge Kutte method for y'=f(t,y);
//solve first order ode in the interval (a,b) with a given initial condition at x=a and fixed step h.
class Runge{
    public delegate double Function(double t,double y); //declare a delegate that takes a double and returns
//double
    public static void runge(double a, double b,double value, double step, Function f)
    {
          double t,w,k1,k2,k3,k4;
        t=a;
        w=value;
        for(int i=0;i<(b-a)/step;i++){
            k1=step*f(t,w);
            k2=step*f(t+step/2,w+k1/2);
            k3=step*f(t+step/2,w+k2/2);
            k4=step*f(t+step,w+k3);
            w=w+(k1+2*k2+2*k3+k4)/6;
            t=a+i*step;
            Console.WriteLine("{0} {1} ",t,w);
           }
    }
}
class Test
{
    public static double f1(double t, double y)
    {
    return -y+t+1;
    }
    public static void Main()
    {
    Runge.runge(0,1,1,.1f,new Runge.Function(Test.f1));
    }
}
 Runge-Kutta methods with a variable step size are often used in practice since they converge faster than fixed size methods.


Lesson 17. Reading a database.


ADO API's are part of  the System.Data.ADO namespace. Bellow I show a very simple Microsoft Access database called Bank_customer_data. The program needs to be compiled with option /r:System.dll /r:System.Data.dll.

I store table Bank_customer_data in a database db2.mdb located in the directory C\Temp. Firstly we would like to read a name and the amount of assets of all customers of the bank. To do that we can use SQL commands SELECT Name, Assets FROM Bank_customer_data. To prepare for data retrieval from the database, we create an instance of ADOCommand class. ADOCommand class takes care of passing queries to the database. ADOCommand instance can be creates by passing the address of the data source as well as the name of the table as string parameters. We will write a slightly longer but more transparent code. We also need an instance of ADOConnection which represents an open connection to the database. We use ADOConnection constructor which takes a string containing the address of the database file. After an instance of the ADOConnection is created we need to open the connection to the database using method Open(). If the connection is already open an InvalidOperationException  is raised. At the end of the session we call Close() to close the connection. If you try to close the connection twice it generates  InvalidOperationException. The instance of ADOCommand needs to be associated with an instance of opened ADOConnection. This is done with the property ActiveConnection. The simplest way to pass the query to the database is to with an instance of ADODataReader class. The result of the query to the database is contained in the instance of the ADODataReader class. To associate the instance of ADODataReader with the address of the database and the query to be made, we call Execute method which takes the instance of the ADODataReader as an out parameter.The actual reading can be done line by line with the call Read(). If you decide to display the line you have just read, it is your responsibility to use the correct data extraction methods. If, for example you are trying to extract a string with GetInt32() method an exception will be raised. Finally, the reader is closed when no longer used.

using System;
using System.Data.ADO;

public class Test{
    public static void Main()
    {
    string source = "Provider=Microsoft.JET.OLEDB.4.0;" + "data     source=""C:\\Winnt\\Profiles\\Administrator\\Personal\\db2.mdb
    string command="SELECT Name, Assets FROM Bank_customer_data";
    ADOCommand mCommand = new ADOCommand(); 
    ADOConnection mConnection=new ADOConnection(source);
    mConnection.Open();
    mCommand.ActiveConnection=mConnection; 
    mCommand.CommandText=command;
    ADODataReader mReader;
    mCommand.Execute(out mReader); 
    // Use Read to  read data line by line.
    while (mReader.Read()) 
        { //The data is extracted with the methods GetString and GetInt32
        Console.WriteLine(mReader.GetString(0) + ":" + mReader.GetInt32(1));
        }
    // Close the Reader when done. 
    mReader.Close();
    // Close the connection when done. 
    mConnection.Close(); 
    }
}