Saturday 7 April 2012

C Sharp Tutorials/Lesson 10 Lesson 10: Properties


Lesson 10: Properties

This lesson teaches C# Properties. Our objectives are as follows:
  • Understand What Properties Are For.
  • Implement a Property.
  • Create a Read-Only Property.
  • Create a Write-Only Property.
  • Create an auto-implemented property.

Overview of Properties

Properties provide the opportunity to protect a field in a class by reading and writing to it through the property. In other languages, this is often accomplished by programs implementing specialized getter and setter methods. C# properties enable this type of protection while also letting you access the property just like it was a field.
Another benefit of properties over fields is that you can change their internal implementation over time. With a public field, the underlying data type must always be the same because calling code depends on the field being the same. However, with a property, you can change the implementation. For example, if a customer has an ID that is originally stored as an int, you might have a requirements change that made you perform a validation to ensure that calling code could never set the ID to a negative value. If it was a field, you would never be able to do this, but a property allows you to make such a change without breaking code. Now, lets see how to use properties.

Traditional Encapsultation Without Properties

Languages that don't have properties will use methods (functions or procedures) for encapsultation. The idea is to manage the values inside of the object, state, avoiding corruption and misuse by calling code. Listing 10-1 demonstrates how this traditional method works, encapsulating Customer information via accessor methods.
Listing 10-1. An Example of Traditional Class Field Access
using System;

public class Customer
{
   private int m_id = -1;

   public int GetID()
   {
       return m_id;
   }

   public void SetID(int id)
   {
       m_id = id;
   }

   private string m_name = string.Empty;

   public string GetName()
   {
       return m_name;
   }

   public void SetName(string name)
   {
       m_name = name;
   }
}

public class CustomerManagerWithAccessorMethods
{
   public static void Main()
   {
       Customer cust = new Customer();

       cust.SetID(1);
       cust.SetName("Amelio Rosales");

       Console.WriteLine(
           "ID: {0}, Name: {1}",
           cust.GetID(),
           cust.GetName());

       Console.ReadKey();
   }
}
Listing 10-1 shows the traditional method of accessing class fields. The Customer class has four properties, two for each private field that the class encapsulates: m_id and m_name. As you can see, SetID and SetName assign a new values and GetID and GetName return values.
Observe how Main calls the SetXxx methods, which sets m_id to 1 and m_name to "Amelio Rosales" in the Customer instance, cust. The call to Console.WriteLine demonstrates how to read m_id and m_name from cust, via GetID and GetName method calls, respectively.
This is such a common pattern, that C# has embraced it in the form of a language feature called properties, which you'll see in the next section.

Encapsulating Type State with Properties

The practice of accessing field data via methods was good because it supported the object-oriented concept of encapsulation. For example, if the type of m_id or m_namechanged from an int type to byte, calling code would still work. Now the same thing can be accomplished in a much smoother fashion with properties, as shown in Listing 10-2.
Listing 10-2. Accessing Class Fields With Properties
using System;

public class Customer
{
   private int m_id = -1;

   public int ID
   {
       get
       {
           return m_id;
       }
       set
       {
           m_id = value;
       }
   }

   private string m_name = string.Empty;

   public string Name
   {
       get
       {
           return m_name;
       }
       set
       {
           m_name = value;
       }
   }
}

public class CustomerManagerWithProperties
{
   public static void Main()
   {
       Customer cust = new Customer();

       cust.ID = 1;
       cust.Name = "Amelio Rosales";

 Console.WriteLine(
           "ID: {0}, Name: {1}",
           cust.ID,
           cust.Name);

       Console.ReadKey();
   }
}
Listing 10-2 shows how to create and use a property. The Customer class has the ID andName property implementations. There are also private fields named m_id and m_name;which ID and Name, respectively, encapsulate. Each property has two accessors, get andset. The accessor returns the value of a field. The set accessor sets the value of a field with the contents of value, which is the value being assigned by calling code. The valueshown in the accessor is a C# reserved word.
When setting a property, just assign a value to the property as if it were a field. TheCustomerManagerWithProperties class uses the ID and Name properties in the Customerclass. The first line of Main instantiates a Customer object named cust. Next the value of the m_id and m_name fields of cust are set by using the ID and Name properties.
To read from a property, use the property as if it were a field. Console.WriteLine prints the value of the m_id and m_name fields of cust. It does this by calling the ID and Nameproperties of cust.
This was a read/write property, but you can also create read-only properties, which you'll learn about next.

Creating Read-Only Properties

Properties can be made read-only. This is accomplished by having only a get accessor in the property implementation. Listing 10-3 demonstrates how you can create a read-only property.
Listing 10-3. Read-Only Properties
using System;

public class Customer
{
   private int m_id = -1;
   private string m_name = string.Empty;

   public Customer(int id, string name)
   {
       m_id = id;
       m_name = name;
   }

   public int ID
   {
       get
       {
           return m_id;
       }
   }

   public string Name
   {
       get
       {
           return m_name;
       }
   }
}

public class ReadOnlyCustomerManager
{
   public static void Main()
   {
       Customer cust = new Customer(1, "Amelio Rosales");

       Console.WriteLine(
           "ID: {0}, Name: {1}",
           cust.ID,
           cust.Name);

       Console.ReadKey();
   }
}
The Customer class in Listing 10-3 has two read-only properties, ID and Name. You can tell that each property is read-only because they only have get accessors. At some time, values for the m_id and m_name must be assigned, which is the role of the constructor in this example.
The Main method of the ReadOnlyCustomerManager class instantiates a new Customerobject named cust. The instantiation of cust uses the constructor of Customer class, which takes int and string type parameters. In this case, the values are 1 and "Amelio Rosales". This initializes the m_id and m_name fields of cust.
Since the ID and Name properties of the Customer class are read-only, there is no other way to set the value of the m_id and m_name fields. If you inserted cust.ID = 7 into the listing, the program would not compile, because ID is read-only; the same goes for Name. When the ID and Name properties are used in Console.WriteLine, they work fine. This is because these are read operations which only invoke the get accessor of the ID and Nameproperties.
One question you might have now is "If a property can be read-only, can it also be write-only?" The answer is yes, and explained in the next section.

Creating a Write-Only Property

You can assign values to, but not read from, a write-only property. A write-only property only has a set accessor. Listing 10-4 shows you how to create and use write-only properties.
Listing 10-4. Write-Only Properties
using System;

public class Customer
{
   private int m_id = -1;

   public int ID
   {
       set
       {
           m_id = value;
       }
   }

   private string m_name = string.Empty;

   public string Name
   {
       set
       {
           m_name = value;
       }
   }

   public void DisplayCustomerData()
   {
       Console.WriteLine("ID: {0}, Name: {1}", m_id, m_name);
   }
}

public class WriteOnlyCustomerManager
{
   public static void Main()
   {
       Customer cust = new Customer();

       cust.ID = 1;
       cust.Name = "Amelio Rosales";

       cust.DisplayCustomerData();

       Console.ReadKey();
   }
}
This time, the get accessor is removed from the ID and Name properties of the Customerclass, shown in Listing 10-1. The set accessors have been added, assigning value to the backing store fields, m_id and m_name.
The Main method of the WriteOnlyCustomerManager class instantiates the Customer class with a default constructor. Then it uses the ID and Name properties of cust to set the m_idand m_name fields of cust to 1 and "Amelio Rosales", respectively. This invokes the setaccessor of ID and Name properties from the cust instance.
When you have a lot of properties in a class or struct, there can also be a lot of code associated with those properties. In the next section, you'll see how to write properties with less code.

Creating Auto-Implemented Properties

The patterns you see here, where a property encapsulates a property with get and setaccessors, without any other logic is common. It is more code than we should have to write for such a common scenario. That's why C# 3.0 introduced a new syntax for a property, called an auto-implemented property, which allows you to create properties without getand set accessor implementations. Listing 10-5 shows how to add auto-implemented properties to a class.
Listing 10-5. Auto-Impemented Properties
using System;

public class Customer
{
   public int ID { get; set; }
   public string Name { get; set; }
}

public class AutoImplementedCustomerManager
{
   static void Main()
   {
       Customer cust = new Customer();

       cust.ID = 1;
       cust.Name = "Amelio Rosales";

       Console.WriteLine(
           "ID: {0}, Name: {1}",
           cust.ID,
           cust.Name);

       Console.ReadKey();
   }
}
Notice how the get and set accessors in Listing 10-5 do not have implementations. In an auto-implemented property, the C# compiler creates the backing store field behind the scenes, giving the same logic that exists with traditional properties, but saving you from having to use all of the syntax of the traditional property. As you can see in the Mainmethod, the usage of an auto-implemented property is exactly the same as traditional properties, which you learned about in previous sections.

C Sharp Tutorials/Lesson 11 Lesson 11: Indexers


This lesson teaches C# Indexers. Our objectives are as follows:
  • Understand What Indexers Are For.
  • Implement an Indexer.
  • Overload Indexers.
  • Understand How to Implement Multi-Parameter Indexers.
Indexers are real easy. They allow your class to be used just like an array. On the inside of a class, you manage a collection of values any way you want. These objects could be a finite set of class members, another array, or some complex data structure. Regardless of the internal implementation of the class, its data can be obtained consistently through the use of indexers. Here's an example.
Listing 11-1. An Example of An Indexer: IntIndexer.cs
using System;
/// 

/// A simple indexer example./// 

class IntIndexer
{
private string[] myData;
public IntIndexer(int size)
{
myData = 
new string[size];
for (int i=0; i < size; i++)
{
myData[i] = "empty";
}
}

public
 string this[int pos]
{
get
{return myData[pos];
}
set
{
myData[pos] = 
value;
}
}

static
 void Main(string[] args)
{
int size = 10;

IntIndexer myInd = 
new IntIndexer(size);

myInd[9] = "Some Value";
myInd[3] = "Another Value";
myInd[5] = "Any Value";

Console.WriteLine("\nIndexer Output\n");

for
 (int i=0; i < size; i++)
{
Console.WriteLine("myInd[{0}]: {1}", i, myInd[i]);
}
}
}
Listing 11-1 shows how to implement an Indexer. The IntIndexer class has a string array named myData. This is a private array that external users can't see. This array is initialized in the constructor, which accepts an int size parameter, instantiates the myData array, and then fills each element with the word "empty".
The next class member is the Indexer, which is identified by the this keyword and square brackets, this[int pos]. It accepts a single position parameter, pos. As you may have already guessed, the implementation of an Indexer is the same as a Property. It has get andset accessors that are used exactly like those in a Property. This indexer returns a string, as indicated by the string return value in the Indexer declaration.
The Main() method simply instantiates a new IntIndexer object, adds some values, and prints the results. Here's the output:
Indexer Output

myInd[0]: empty
myInd[1]: empty
myInd[2]: empty
myInd[3]: Another Value
myInd[4]: empty
myInd[5]: Any Value
myInd[6]: empty
myInd[7]: empty
myInd[8]: empty
myInd[9]: Some Value
Using an integer is a common means of accessing arrays in many languages, but the C# Indexer goes beyond this. Indexers can be declared with multiple parameters and each parameter may be a different type. Additional parameters are separated by commas, the same as a method parameter list. Valid parameter types for Indexers include integers,enums, and strings. Additionally, Indexers can be overloaded. In listing 11-2, we modify the previous program to accept overloaded Indexers that accept different types.
Listing 11-2. Overloaded Indexers: OvrIndexer.cs
using System;
/// 

/// Implements overloaded indexers./// 

class OvrIndexer
{
private string[] myData;private int arrSize;
public OvrIndexer(int size)
{
arrSize = size;
myData = 
new string[size];
for (int i=0; i < size; i++)
{
myData[i] = "empty";
}
}

public
 string this[int pos]
{
get
{return myData[pos];
}
set
{
myData[pos] = 
value;
}
}

public
 string this[string data]
{
get
{int count = 0;
for
 (int i=0; i < arrSize; i++)
{
if (myData[i] == data)
{
count++;
}
}
return count.ToString();
}
set
{for (int i=0; i < arrSize; i++)
{
if (myData[i] == data)
{
myData[i] = 
value;
}
}
}
}

static
 void Main(string[] args)
{
int size = 10;
OvrIndexer myInd = 
new OvrIndexer(size);

myInd[9] = "Some Value";
myInd[3] = "Another Value";
myInd[5] = "Any Value";

myInd["empty"] = "no value";

Console.WriteLine("\nIndexer Output\n");

for
 (int i=0; i < size; i++)
{
Console.WriteLine("myInd[{0}]: {1}", i, myInd[i]);
}

Console.WriteLine("\nNumber of \"no value\" entries: {0}", myInd["no value"]);
}
}
Listing 11-2 shows how to overload Indexers. The first Indexer, with the int parameter, pos, is the same as in Listing 11-1, but there is a new Indexer that takes a string parameter. The get accessor of the new indexer returns a string representation of the number of items that match the parameter value, data. The set accessor changes each entry in the array that matches the data parameter to the value that is assigned to the Indexer.
The behavior of the overloaded Indexer that takes a string parameter is demonstrated in the Main() method of Listing 11-2. It invokes the set accessor, which assigns the value of "no value" to every member of the myInd class that has the value of "empty". It uses the following command: myInd["empty"] = "no value";. After each entry of the myInd class is printed, a final entry is printed to the console, indicating the number of entries with the "no value" string. This happens by invoking the get accessor with the following code: myInd["no value"]. Here's the output:
Indexer Output

myInd[0]: no value
myInd[1]: no value
myInd[2]: no value
myInd[3]: Another Value
myInd[4]: no value
myInd[5]: Any Value
myInd[6]: no value
myInd[7]: no value
myInd[8]: no value
myInd[9]: Some Value

Number of "no value" entries: 7
The reason both Indexers in Listing 11-2 can coexist in the same class is because they have different signatures. An Indexer signature is specified by the number and type of parameters in an Indexers parameter list. The class will be smart enough to figure out which Indexer to invoke, based on the number and type of arguments in the Indexer call. An indexer with multiple parameters would be implemented something like this:
public object this[int param1, ..., int paramN]
{
get
{// process and return some class data
}
set
{
// process and assign some class data
}
}

C Sharp Tutorials/Lesson 12 Lesson 12: Structs


This lesson teaches C# Structs. Our objectives are as follows:
  • Understand the Purpose of structs.
  • Implement a struct.
  • Use a struct.
struct allows you to create new value-type objects that are similar to the built-in types (intfloatbool, etc.). When would you use a struct instead of a class? Think about how the built-in types are used. They have values and distinct operations to manipulate those values. If you have a need to create an object that behaves in this manner, consider implementing it as a struct. Later in this article, I'll explain a couple rules for using structs, which will give you a better idea of when to use them. In the meantime, here's an example.
Listing 12-1. Example of a struct: StructExample.cs
using System;
struct Point
{
public int x;public int y;
public
 Point(int x, int y)
{
this.x = x;this.y = y;
}

public
 Point Add(Point pt)
{
Point newPt;

newPt.x = x + pt.x;
newPt.y = y + pt.y;

return
 newPt;
}
}
/// 

/// Example of declaring and using a struct/// 

class StructExample
{
static void Main(string[] args)
{
Point pt1 = 
new Point(1, 1);
Point pt2 = 
new Point(2, 2);
Point pt3;

pt3 = pt1.Add(pt2);

Console.WriteLine("pt3: {0}:{1}", pt3.x, pt3.y);
}
}
Listing 12-1 shows how to declare and use a struct. It is easy to tell that a type is a structbecause of the keyword struct used in its definition. The basic layout of a struct is much like a class, but with differences, which will be explained in following paragraphs. The Pointstruct has a constructor which initializes its fields to the and y values passed in. It also has a method named Add(), which will accept another Point struct, add it to this struct, and return a new struct.
Notice that there is a Point struct declared in the Add() method. It does not need to be instantiated with a new operator, like a class. When this occurs, the struct is implicitly instantiated with its default (or parameterless) constructor. The parameterless constructor initializes all struct fields to default values. i.e. integrals are 0, floating points are 0.0, and booleans are false. It's illegal to define a parameterless constructor for a struct.
Although not required, a struct may be instantiated with a new operator. In Listing 12-1 thept1 and pt2 Point structs are initialized with values by using the constructor defined in thePoint struct. A third Point structpt3 is declared and defaults to using the parameterless (default) constructor, because it doesn't matter what it's value is at this point. The Add()method of the pt1 struct is then invoked, passing the pt2 struct as a parameter. The result is assigned to pt3, showing that a struct may be used just like any other value type. Here's the output from Listing 12-1:
 pt3: 3:3
Another difference between structs and classes is that structs can not have destructors. Also, structs cannot inherit another class or struct or be inherited from. However, a structmay implement multiple interfaces. An interface is a C# reference type with members that do not have implementations. Any class or struct implementing an interface must implement every one of that interface's methods. Interfaces are a subject for a later lesson.

C Sharp Tutorials/Lesson 13 Lesson 13: Interfaces


This lesson teaches C# Interfaces. Our objectives are as follows:
  • Understand the Purpose of Interfaces.
  • Define an Interface.
  • Use an Interface.
  • Implement Interface Inheritance.
An interface looks like a class, but has no implementation. The only thing it contains are definitions of eventsindexersmethods and/or properties. The reason interfaces only provide definitions is because they are inherited by classes and structs, which must provide an implementation for each interface member defined.
So, what are interfaces good for if they don't implement functionality? They're great for putting together plug-n-play like architectures where components can be interchanged at will. Since all interchangeable components implement the same interface, they can be used without any extra programming. The interface forces each component to expose specific public members that will be used in a certain way.
Because interfaces must be implemented by derived classes and structs, they define a contract. For instance, if class foo implements the IDisposable interface, it is making a statement that it guarantees it has the Dispose() method, which is the only member of theIDisposable interface. Any code that wishes to use class foo may check to see if class fooimplements IDisposable. When the answer is true, then the code knows that it can callfoo.Dispose(). Listing 13-1 shows how to define an interface:
Listing 13-1. Defining an Interface: MyInterface.cs
interface IMyInterface
{
void MethodToImplement();
}
Listing 13-1 defines an interface named IMyInterface. A common naming convention is to prefix all interface names with a capital "I". This interface has a single method namedMethodToImplement(). This could have been any type of method declaration with different parameters and return types. I just chose to declare this method with no parameters and avoid return type to make the example easy. Notice that this method does not have an implementation (instructions between curly braces - {}), but instead ends with a semi-colon, ";". This is because the interface only specifies the signature of methods that an inheriting class or struct must implement. Listing 13-2 shows how this interface could be used.
Listing 13-2. Using an Interface: InterfaceImplementer.cs
class InterfaceImplementer : IMyInterface
{
static void Main()
{
InterfaceImplementer iImp = 
new InterfaceImplementer();
iImp.MethodToImplement();
}

public
 void MethodToImplement()
{
Console.WriteLine("MethodToImplement() called.");
}
}
The InterfaceImplementer class in Listing 13.2 implements the IMyInterface interface. Indicating that a class inherits an interface is the same as inheriting a class. In this case, the following syntax is used:
class InterfaceImplementer : IMyInterface
Now that this class inherits the IMyInterface interface, it must implement its members. It does this by implementing the MethodToImplement() method. Notice that this method implementation has the exact same signature, parameters and method name, as defined in the IMyInterface interface. Any difference between the method signature in the interface and the method signature in the implementing class or struct will cause a compiler error. Additionally, a class or struct that inherits an interface must include all interface members; You will receive a compiler error if you don't implement all interface members.
Interfaces may also inherit other interfaces. Listing 13-3 shows how inherited interfaces are implemented.
Listing 13-3. Interface Inheritance: InterfaceInheritance.cs
using System;
interface IParentInterface
{
void ParentInterfaceMethod();
}

interface
 IMyInterface : IParentInterface
{
void MethodToImplement();
}

class
 InterfaceImplementer : IMyInterface
{
static void Main()
{
InterfaceImplementer iImp = 
new InterfaceImplementer();
iImp.MethodToImplement();
iImp.ParentInterfaceMethod();
}

public
 void MethodToImplement()
{
Console.WriteLine("MethodToImplement() called.");
}
public void ParentInterfaceMethod()
{
Console.WriteLine("ParentInterfaceMethod() called.");
}
}
The code in listing 13.3 contains two interfacesIMyInterface and the interface it inherits,IParentInterface. When one interface inherits another, any implementing class or structmust implement every interface member in the entire inheritance chain. Since theInterfaceImplementer class in Listing 13-3 inherits from IMyInterface, it also inheritsIParentInterface. Therefore, the InterfaceImplementer class must implement theMethodToImplement() method specified in the IMyInterface interface and theParentInterfaceMethod() method specified in the IParentInterface interface.

C Sharp Tutorials/Lesson 14 Lesson 14: Introduction to Delegates and Events


This lesson introduces delegates and events. Our objectives are as follows:
  • Understand What a Delegate Is
  • Understand What an Event Is
  • Implement Delegates
  • Fire Events

Delegates

During previous lessons, you learned how to implement reference types using language constructs such as classes and interfaces. These reference types allowed you to create instances of objects and use them in special ways to accomplish your software development goals. Classes allow you to create objects that contained members with attributes or behavior. Interfaces allow you to declare a set of attributes and behavior that all objects implementing them would publicly expose. Today, I'm going to introduce a new reference type called a delegate.
delegate is a C# language element that allows you to reference a method. If you were a C or C++ programmer, this would sound familiar because a delegate is basically a function pointer. However, developers who have used other languages are probably wondering, "Why do I need a reference to a method?". The answer boils down to giving you maximum flexibility to implement any functionality you want at runtime.
Think about how you use methods right now. You write an algorithm that does its thing by manipulating the values of variables and calling methods directly by name. What if you wanted an algorithm that was very flexible, reusable, and allowed you to implement different functionality as the need arises? Furthermore, let's say that this was an algorithm that supported some type of data structure that you wanted to have sorted, but you also want to enable this data structure to hold different types. If you don't know what the types are, how could you decide an appropriate comparison routine? Perhaps you could implement anif/then/else or switch statement to handle well-known types, but this would still be limiting and require overhead to determine the type. Another alternative would be for all the types to implement an interface that declared a common method your algorithm would call, which is actually a nice solution. However, since this lesson is about delegates, we'll apply adelegate solution, which is quite elegant.
You could solve this problem by passing a delegate to your algorithm and letting the contained method, which the delegate refers to, perform the comparison operation. Such an operation is performed in Listing 14-1.
Listing 14-1. Declaring and Implementing a Delegate: SimpleDelegate.cs
using System;
// this is the delegate declarationpublic delegate int Comparer(object obj1, object obj2);
public class Name
{
public string FirstName = null;public string LastName = null;
public
 Name(string first, string last)
{
FirstName = first;
LastName = last;
}
// this is the delegate method handler
public
 static int CompareFirstNames(object name1, object name2)
{
string n1 = ((Name)name1).FirstName;string n2 = ((Name)name2).FirstName;
if
 (String.Compare(n1, n2) > 0)
{
return 1;
}
else if (String.Compare(n1, n2) < 0)
{
return -1;
}
else{return 0;
}
}

public
 override string ToString()
{
return FirstName + " " + LastName;
}
}

class
 SimpleDelegate
{
Name[] names = 
new Name[5];
public
 SimpleDelegate()
{
names[0] = 
new Name("Joe", "Mayo");
names[1] = 
new Name("John", "Hancock");
names[2] = 
new Name("Jane", "Doe");
names[3] = 
new Name("John", "Doe");
names[4] = 
new Name("Jack", "Smith");
}

static
 void Main(string[] args)
{
SimpleDelegate sd = 
new SimpleDelegate();
// this is the delegate instantiationComparer cmp = new Comparer(Name.CompareFirstNames);

Console.WriteLine("\nBefore Sort: \n");

sd.PrintNames();
// observe the delegate argumentsd.Sort(cmp);

Console.WriteLine("\nAfter Sort: \n");

sd.PrintNames();
}

// observe the delegate parameterpublic void Sort(Comparer compare)
{
object temp;
for
 (int i=0; i < names.Length; i++)
{
for (int j=i; j < names.Length; j++)
{
// using delegate "compare" just like
// a normal method
if ( compare(names[i], names[j]) > 0 )
{
temp = names[i];
names[i] = names[j];
names[j] = (Name)temp;
}
}
}
}

public
 void PrintNames()
{
Console.WriteLine("Names: \n");

foreach
 (Name name in names)
{
Console.WriteLine(name.ToString());
}
}
}
The first thing the program in Listing 14-1 does is declare a delegateDelegate declarations look somewhat like methods, except they have the delegate modifier, are terminated with a semi-colon (;), and have no implementation. Below, is the delegate declaration from Listing 14-1.
public delegate int Comparer(object obj1, object obj2);
This delegate declaration defines the signature of a delegate handler method that thisdelegate can refer to. The delegate handler method, for the Comparer delegate, can have any name, but must have a first parameter of type object, a second parameter of typeobject, and return an int type. The following method from Listing 14-1 shows a delegate handler method that conforms to the signature of the Comparer delegate.
public static int CompareFirstNames(object name1, object name2)
{
...
}
Note: The CompareFirstNames method calls String.Compare to compare the FirstNameproperties of the two Name instances. The String class has many convenience methods, such as Compare, for working with strings. Please don't allow the implementation of this method to interfere with learning how delegates work. What you should concentrate on is that CompareFirstNames is a handler method that a delegate can refer to, regardless of the code inside of that method.
To use a delegate, you must create an instance of it. The instance is created, similar to a class instance, with a single parameter identifying the appropriate delegate handler method, as shown below.
Comparer cmp = new Comparer(Name.CompareFirstNames);
The delegatecmp, is then used as a parameter to the Sort() method, which uses it just like a normal method. Observe the way the delegate is passed to the Sort() method as a parameter in the code below.
sd.Sort(cmp);
Using this technique, any delegate handler method may be passed to the Sort() method at run-time. i.e. You could define a method handler named CompareLastNames(), instantiate a new Comparer delegate instance with it, and pass the new delegate to the Sort() method.

Events

Traditional Console applications operate by waiting for a user to press a key or type a command and press the Enter key. Then they perform some pre-defined operation and either quit or return to the original prompt that they started from. This works, but is inflexible in that everything is hard-wired and follows a rigid path of execution. In stark contrast, modern GUI programs operate on an event-based model. That is, some event in the system occurs and interested modules are notified so they can react appropriately. With Windows Forms, there is not a polling mechanism taking up resources and you don't have to code a loop that sits waiting for input. It is all built into the system with events.
A C# event is a class member that is activated whenever the event it was designed for occurs. I like to use the term "fires" when the event is activated. Anyone interested in theevent can register and be notified as soon as the event fires. At the time an event fires, registered methods will be invoked.
Events and delegates work hand-in-hand to provide a program's functionality. It starts with a class that declares an event. Any class, including the same class that the event is declared in, may register one of its methods for the event. This occurs through a delegate, which specifies the signature of the method that is registered for the event. The delegatemay be one of the pre-defined .NET delegates or one you declare yourself. Whichever is appropriate, you assign the delegate to the event, which effectively registers the method that will be called when the event fires. Listing 14-2 shows a couple different ways to implement events.
Listing 14-2. Declaring and Implementing Events: Eventdemo.cs
using System;using System.Drawing;using System.Windows.Forms;
// custom delegatepublic delegate void Startdelegate();
class Eventdemo : Form
{

// custom eventpublic event Startdelegate StartEvent;
public Eventdemo()
{
Button clickMe = 
new Button();

clickMe.Parent = 
this;
clickMe.Text = "Click Me";
clickMe.Location = 
new Point(
(ClientSize.Width - clickMe.Width) /2,
(ClientSize.Height - clickMe.Height)/2);
// an EventHandler delegate is assigned
// to the button's Click event
clickMe.Click += new EventHandler(OnClickMeClicked);
// our custom "Startdelegate" delegate is assigned
// to our custom "StartEvent" event.
StartEvent += new Startdelegate(OnStartEvent);
// fire our custom eventStartEvent();
}

// this method is called when the "clickMe" button is pressed
public void OnClickMeClicked(object sender, EventArgs ea)
{
MessageBox.Show("You Clicked My Button!");
}

// this method is called when the "StartEvent" Event is firedpublic void OnStartEvent()
{
MessageBox.Show("I Just Started!");
}

static
 void Main(string[] args)
{
Application.Run(
new Eventdemo());
}
}
Note: If you're using Visual Studio or another IDE, remember to add references to System.Drawing.dll and System.Windows.Forms.dll before compiling Listing 14.2 or just add the code to a Windows Forms project. Teaching the operation of Visual Studio or other IDE's is out-of-scope for this tutorial.
You may have noticed that Listing 14-2 is a Windows Forms program. Although I haven't covered Windows Forms in this tutorial, you should know enough about C# programming in general that you won't be lost. To help out, I'll give a brief explanation of some of the parts that you may not be familiar with.
The Eventdemo class inherits Form, which essentially makes it a Windows Form. This automatically gives you all the functionality of a Windows Form, including Title Bar, Minimize/Maximize/Close buttons, System Menu, and Borders. A lot of power, that inheritance thing, eh?
The way a Windows Form's application is started is by calling the Run() method of the staticApplication object with a reference to the form object as its parameter. This starts up all the underlying Windows plumbing, displays the GUI, and ensures that events are fired as appropriate.
Let's look at the custom event first. Below is the event declaration, which is a member of the Eventdemo class. It is declared with the event keyword, a delegate type, and an eventname.
public event Startdelegate StartEvent;
Anyone interested in an event can register by hooking up a delegate for that event. On the next line, we have a delegate of type Startdelegate, which the event was declared to accept, hooked up to the StartEvent event. The += syntax registers a delegate with anevent. To unregister with an event, use the -= with the same syntax.
StartEvent += new Startdelegate(OnStartEvent);
Firing an event looks just like a method call, as shown below:
StartEvent();
This was how to implement events from scratch, declaring the event and delegate yourself. However, much of the event programming you'll do will be with pre-defined events anddelegates. This leads us to the other event code you see in Listing 14-2, where we hook up an EventHandler delegate to a Button Click event.
clickMe.Click += new EventHandler(OnClickMeClicked);
The Click event already belongs to the Button class and all we have to do is reference it when registering a delegate. Similarly, the EventHandler delegate already exists in theSystem namespace of the .NET Frameworks Class Library. All you really need to do is define your callback method (delegate handler method) that is invoked when someone presses theclickMe button. The OnClickMeClicked() method, shown below, conforms to the signature of the EventHander delegate, which you can look up in the .NET Framework Class Library reference.
public void OnClickMeClicked(object sender, EventArgs ea)
{
MessageBox.Show("You Clicked My Button!");
}
Any time the clickMe button is pressed with a mouse, it will fire the Click event, which will invoke the OnClickMeClicked() method. The Button class takes care of firing the Click eventand there's nothing more you have to do. Because it is so easy to use pre-defined eventsand delegates, it would be a good idea to check if some exist already that will do what you need, before creating your own.