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.
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.
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.
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.
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();
}
}
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!
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 i we need to pass it by reference. When passing by reference compiler changes i 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
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?
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++.
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!
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.
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.
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. |
.
Other interesting commands are:
There are also other elements which I will explain in more detail after I write an introduction to XML.
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));
}
}
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
}
}
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.
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!
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!
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.
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();
}
}