/* * C# Programmers Pocket Consultant * Author: Gregory S. MacBeth * Email: gmacbeth@comporium.net * Create Date: June 27, 2003 * Last Modified Date: */ using System; namespace Client.Chapter_8___Delegates_and_Events { public class DelegatesChapter_8___Delegates_and_Events { delegate int MyDelegate(string s); static void Main(string[] args) { MyDelegate Del1 = new MyDelegate(DoSomething); MyDelegate Del2 = new MyDelegate(DoSomething2); string MyString = "Hello World"; Del1(MyString); Del2(MyString); //Or you can Multicast delegates by doing this MyDelegate Multicast = null; Multicast += new MyDelegate(DoSomething); Multicast += new MyDelegate(DoSomething2); //Both DoSomething & DoSomething2 will be fired //in the order they are added to the delegate Multicast(MyString); Multicast -= new MyDelegate(DoSomething2); } static int DoSomething(string s) { return 0; } static int DoSomething2(string s) { return 0; } } }
Language Basics
Delegates can refer to instance methods, too
/* C#: The Complete Reference by Herbert Schildt Publisher: Osborne/McGraw-Hill (March 8, 2002) ISBN: 0072134852 */ // Delegates can refer to instance methods, too. using System; // Declare a delegate. delegate string strMod(string str); class StringOps { // Replaces spaces with hyphens. public string replaceSpaces(string a) { Console.WriteLine("Replaces spaces with hyphens."); return a.Replace(' ', '-'); } // Remove spaces. public string removeSpaces(string a) { string temp = ""; int i; Console.WriteLine("Removing spaces."); for(i=0; i < a.Length; i++) if(a[i] != ' ') temp += a[i]; return temp; } // Reverse a string. public string reverse(string a) { string temp = ""; int i, j; Console.WriteLine("Reversing string."); for(j=0, i=a.Length-1; i >= 0; i--, j++) temp += a[i]; return temp; } } public class DelegateTest1 { public static void Main() { StringOps so = new StringOps(); // create an instance of StringOps // Construct a delegate. strMod strOp = new strMod(so.replaceSpaces); string str; // Call methods through delegates. str = strOp("This is a test."); Console.WriteLine("Resulting string: " + str); Console.WriteLine(); strOp = new strMod(so.removeSpaces); str = strOp("This is a test."); Console.WriteLine("Resulting string: " + str); Console.WriteLine(); strOp = new strMod(so.reverse); str = strOp("This is a test."); Console.WriteLine("Resulting string: " + str); } }
A simple delegate example
/* C#: The Complete Reference by Herbert Schildt Publisher: Osborne/McGraw-Hill (March 8, 2002) ISBN: 0072134852 */ // A simple delegate example. using System; // Declare a delegate. delegate string strMod(string str); public class DelegateTest { // Replaces spaces with hyphens. static string replaceSpaces(string a) { Console.WriteLine("Replaces spaces with hyphens."); return a.Replace(' ', '-'); } // Remove spaces. static string removeSpaces(string a) { string temp = ""; int i; Console.WriteLine("Removing spaces."); for(i=0; i < a.Length; i++) if(a[i] != ' ') temp += a[i]; return temp; } // Reverse a string. static string reverse(string a) { string temp = ""; int i, j; Console.WriteLine("Reversing string."); for(j=0, i=a.Length-1; i >= 0; i--, j++) temp += a[i]; return temp; } public static void Main() { // Construct a delegate. strMod strOp = new strMod(replaceSpaces); string str; // Call methods through the delegate. str = strOp("This is a test."); Console.WriteLine("Resulting string: " + str); Console.WriteLine(); strOp = new strMod(removeSpaces); str = strOp("This is a test."); Console.WriteLine("Resulting string: " + str); Console.WriteLine(); strOp = new strMod(reverse); str = strOp("This is a test."); Console.WriteLine("Resulting string: " + str); } }
Demonstrate using a static delegate without declaring an instance of the class
/* C# Programming Tips & Techniques by Charles Wright, Kris Jamsa Publisher: Osborne/McGraw-Hill (December 28, 2001) ISBN: 0072193794 */ // StaticDl.cs -- Demonstrate using a static delegate without declaring // an instance of the class. // // Compile this program with the following command line: // C:>csc StaticDl.cs using System; namespace nsDelegates { public class StaticDl { public delegate void StringHandler (string str); static public StringHandler DoString; static public void Main () { // Create a delegate in this class DoString = new StringHandler (ShowString); DoString ("Static delegate called"); // // Show that the static constructor in another class is shared by instances clsDelegate.DoMath = new clsDelegate.MathHandler (SquareRoot); clsDelegate dlg1 = new clsDelegate (49); clsDelegate dlg2 = new clsDelegate (3.14159); } // The method used with the string delegate static private void ShowString (string str) { Console.WriteLine (str); } // The method used with the double delegate static private double SquareRoot (double val) { double result = Math.Sqrt (val); Console.WriteLine ("The square root of " + val + " is " + result); return (result); } } class clsDelegate { public delegate double MathHandler (double val); static public MathHandler DoMath; // The constructor invokes the delegate if it is not null. public clsDelegate (double val) { value = val; if (DoMath != null) sqrt = DoMath (value); } double value; double sqrt = 0; } }
Using a delegate with a container class to sort the collection and return a sorted array using different sort criteria
/* C# Programming Tips & Techniques by Charles Wright, Kris Jamsa Publisher: Osborne/McGraw-Hill (December 28, 2001) ISBN: 0072193794 */ // SortEmpl.cs -- Demonstrates using a delegate with a container class to // sort the collection and return a sorted array using different // sort criteria. // // Compile this program with the following command line: // C:>csc SortEmpl.cs using System; using System.ComponentModel; namespace nsDelegates { public class SortEmpl { // Declare an enum for the sort methods. enum SortBy {Name, ID, ZIP}; // Create a container to get the clsEmployee object collection static public clsEmployeeContainer container = new clsEmployeeContainer (); static public void Main () { container.Add (new clsEmployee ("John", "Smith", "87678", 1234)); container.Add (new clsEmployee ("Marty", "Thrush", "80123", 1212)); container.Add (new clsEmployee ("Milton", "Aberdeen", "87644", 1243)); container.Add (new clsEmployee ("Marion", "Douglas", "34567", 3454)); container.Add (new clsEmployee ("Johnathon", "Winters", "53422", 3458)); container.Add (new clsEmployee ("William", "Marmouth", "12964", 3658)); container.Add (new clsEmployee ("Miles", "O'Brien", "63445", 6332)); container.Add (new clsEmployee ("Benjamin", "Sisko", "57553", 9876)); // Show the unsorted employee list. Console.WriteLine ("Unsorted employee list:"); ComponentCollection collectionList = container.GetEmployees(); foreach (clsEmployee emp in collectionList) { Console.WriteLine (" " + emp); } // Sort the employees by last name and show the list. Console.WriteLine (" Sorted by last name:"); clsEmployee [] arr = SortList (SortBy.Name); foreach (clsEmployee emp in arr) { Console.WriteLine (" " + emp); } // Sort the employees by ID number and show the list. Console.WriteLine (" Sorted by employee ID:"); arr = SortList (SortBy.ID); foreach (clsEmployee emp in arr) { Console.WriteLine (" " + emp); } // Sort the employees by ZIP code and show the list. Console.WriteLine (" Sorted by ZIP code:"); arr = SortList (SortBy.ZIP); foreach (clsEmployee emp in arr) { Console.WriteLine (" " + emp); } } // Define a method that will create the proper delegate according to // the sort that is needed. static clsEmployee [] SortList (SortBy iSort) { clsEmployeeContainer.CompareItems sort = null; switch (iSort) { case SortBy.Name: sort = new clsEmployeeContainer.CompareItems(clsEmployee.CompareByName); break; case SortBy.ID: sort = new clsEmployeeContainer.CompareItems(clsEmployee.CompareByID); break; case SortBy.ZIP: sort = new clsEmployeeContainer.CompareItems(clsEmployee.CompareByZip); break; } // Do the sort and return the sorted array to the caller. return (container.SortItems (sort, false)); } } public class clsEmployee : Component { // Define an employee class to hold one employee's information. public clsEmployee (string First, string Last, string Zip, int ID) { FirstName = First; LastName = Last; EmployeeID = ID; ZipCode = Zip; } public string FirstName; public string LastName; public string ZipCode; public int EmployeeID; // Define a method to sort by name static public int CompareByName (object o1, object o2) { clsEmployee emp1 = (clsEmployee) o1; clsEmployee emp2 = (clsEmployee) o2; return (String.Compare (emp1.LastName, emp2.LastName)); } // Define a method to sort by ZIP code static public int CompareByZip (object o1, object o2) { clsEmployee emp1 = (clsEmployee) o1; clsEmployee emp2 = (clsEmployee) o2; return (String.Compare (emp1.ZipCode, emp2.ZipCode)); } // Define a method to sort by employee ID number. static public int CompareByID (object o1, object o2) { clsEmployee emp1 = (clsEmployee) o1; clsEmployee emp2 = (clsEmployee) o2; return (emp1.EmployeeID - emp2.EmployeeID); } // Override ToString() for diagnostic purposes public override string ToString () { return (FirstName + " " + LastName + ", ZIP " + ZipCode + ", ID " + EmployeeID); } } // Derive a class to hold the clsEmployee objects public class clsEmployeeContainer { private Container cont = new Container(); public void Add (clsEmployee empl) { cont.Add (empl); } // Declare an array to return to the caller clsEmployee [] arrEmployee; // Declare a delegate to compare one employee object to another public delegate int CompareItems (object obj1, object obj2); // Define a sort function that takes a delegate as a parameter. The Reverse // parameter can be used to reverse the sort. public clsEmployee [] SortItems (CompareItems sort, bool Reverse) { // Get the clsEmployee objects in the container. ComponentCollection employees = cont.Components; // Create an array large enough to hold the references arrEmployee = new clsEmployee[employees.Count]; // Copy the collection into the reference. The Container class will not // let us sort the collection itself. employees.CopyTo (arrEmployee, 0); // Do a simple bubble sort. There are more efficient sorting algorithms, // but a simple sort is all we need. while (true) { int sorts = 0; for (int x = 0; x < arrEmployee.Length - 1; ++x) { int result; // Sort in the reverse order if if the Reverse parameter equals true if (Reverse == true) result = sort (arrEmployee[x + 1], arrEmployee[x]); else result = sort (arrEmployee[x], arrEmployee[x + 1]); // Reverse the two elements if the result is greater than zero if (result > 0) { clsEmployee temp = arrEmployee[x]; arrEmployee[x] = arrEmployee[x+1]; arrEmployee[x+1] = temp; ++sorts; } } // If we did no sorts on this go around, the sort is complete. if (sorts == 0) break; } // Return the sorted array to the caller. return (arrEmployee); } // Return the collection to the caller. public ComponentCollection GetEmployees () { return (cont.Components); } } }
Demonstrates adding multiple methods to a delegate
/* C# Programming Tips & Techniques by Charles Wright, Kris Jamsa Publisher: Osborne/McGraw-Hill (December 28, 2001) ISBN: 0072193794 */ // MultiDlg.cs -- Demonstrates adding multiple methods to a delegate. // // Compile this program with the following command line // C:>csc MultiDlg.cs using System; namespace nsDelegates { public class MultiDlg { public delegate void MultiMethod (); static public void Main () { MultiMethod dlg; // Assign the first method to the delegate. dlg = new MultiMethod (FirstDelegate); // Call it to show the first method is being called dlg (); // Add a second method to the delegate. dlg += new MultiMethod (SecondDelegate); // Call it to show both methods execute. Console.WriteLine (); dlg (); // Remove the first method from the delegate. dlg -= new MultiMethod (FirstDelegate); // Call it to show that only the second method executes Console.WriteLine (); dlg (); } static public void FirstDelegate() { Console.WriteLine ("First delegate called"); } static public void SecondDelegate() { Console.WriteLine ("Second delegate called"); } } }
Demonstrate getting and printing the invocation list for a delegate
/* C# Programming Tips & Techniques by Charles Wright, Kris Jamsa Publisher: Osborne/McGraw-Hill (December 28, 2001) ISBN: 0072193794 */ // InvkList.cs -- Demonstrate getting and printing the invocation list // for a delegate. // // Compile this program with the following command line: // C:>csc InvkList.cs using System; using System.Reflection; namespace nsDelegates { public class DelegatesList { public delegate void ListHandler (); public ListHandler DoList; static public void Main () { DelegatesList main = new DelegatesList (); main.DoList += new ListHandler (DelegateMethodOne); main.DoList += new ListHandler (DelegateMethodThree); main.DoList += new ListHandler (DelegateMethodTwo); Delegate [] dlgs = main.DoList.GetInvocationList (); foreach (Delegate dl in dlgs) { MethodInfo info = dl.Method; Console.WriteLine (info.Name); info.Invoke (main, null); } } static void DelegateMethodOne () { Console.WriteLine ("In delegate method one"); } static void DelegateMethodTwo () { Console.WriteLine ("In delegate method two"); } static void DelegateMethodThree () { Console.WriteLine ("In delegate method three"); } } }