Delegates and Events |
|
Fundamentals of Delegates |
Introduction |
The C and C++ languages have long used the concept of function pointer. This was even more useful when programming for the Microsoft Windows operating systems because the Win32 library relies on the concept of callback functions. Callback functions are used in Microsoft Windows programming to process messages. For this reason and because of their functionality, callback functions were carried out in the .NET Framework but they were defined with the name of delegate. |
A delegate is a special type of user-defined variable that is declared globally, like a class. A delegate provides a template for a method, like an interface provides a template for a class. Like an interface, a delegate is not defined. Its role is to show what a useful method would look like. To support this concept, a delegate can provide all the necessary information that would be used on a method. This includes a return type, no argument or one or more arguments.
|
To create a delegate, you use the delegate keyword. The basic formula used to create a delegate is: [attributes] [modifiers] delegate ReturnType Name ([formal-parameters]); The attributes factor can be a normal C# attribute. The modifier can be one or an appropriate combination of the following keywords: new, public, private, protected, or internal. The delegate keyword is required. The ReturnType can be any of the data types we have used so far. It can also be a type void or the name of a class. The Name must be a valid C# name. Because a delegate is some type of a template for a method, you must use parentheses, required for every method. If this method will not take any argument, leave the parentheses empty. Here is an example: using System; public delegate void Simple(); public class Program { static int Main() { return 0; } } After declaring a delegate, it only provides a template for a method, not an actual method. In order to use it, you must define a method that would carry an assignment to perform. That method must have the same return type and the same (number of) argument(s), if any. For example, the above declared delegate is of type void and it does not take any argument. you can define a corresponding method as follows: public delegate void Simple(); public class Exercise { public void Welcome() { Console.WriteLine("Welcome to the Wonderful World of C# Programming!"); } } With such a method implemented, you can associate it to the name of the delegate. To do that, where you want to use the method, declare a variable of the type of the delegate and assign the method to the delegate variable. Because you are assigning the method to a delegate, one of the rules of delegates is that you must not apply the parentheses to the method. Here is an example public class Program { static int Main() { Exercise exo = new Exercise(); Simple msg = exo.Welcome; return 0; } }
Once you have assigned a method to a delegate variable, you can you the delegate variable as if it were a defined method. That is, you can call as you would a normal method. Here is an example: using System; using System.Collections.Generic; using System.Linq; using System.Text; public delegate void Simple(); public class Exercise { public void Welcome() { Console.WriteLine("Welcome to the Wonderful World of C# Programming!"); } } namespace Delegates { public class Program { static int Main() { Exercise exo = new Exercise(); Simple msg = exo.Welcome; msg(); return 0; } } } This would produce: Welcome to the Wonderful World of C# Programming! Press any key to continue . . .
In the above example, we had to declare a variable of the (Exercise) class before accessing the method. An alternative is to create the associated method as static. That way, you would not need to declare the variable first. Here is an example: using System; public delegate void Simple(); public class Exercise { public static void Welcome() { Console.WriteLine("Welcome to the Wonderful World of C# Programming!"); } } public class Program { static int Main() { Simple msg = Exercise.Welcome; msg(); return 0; } }
In the above examples, we had to create a method that would be associated with a delegate. You can create a delegate, then, when you need to use, create a type of local implementation of a method and use it. In other words, you do not have to explicitly define a method prior to using the delegate. Such a method is referred to as anymous. Before implementing an anonymous method, first declare the delegate you will use: using System; public delegate void Simple(); public class Program { static int Main() { return 0; } } To create an anonymous method, declare a variable for the delegate and assign it the delegate keyword as if it were a method. That is, followed by parentheses and curly brackets that would represent the body of the method. In the body of the anonymous method, do whatever you want. Here is an example: using System; public delegate void Simple(); public class Program { static int Main() { Simple msg = delegate() { Console.WriteLine("Welcome to the Wonderful World of C# Programming!"); }; return 0; } } Once you have done this, you can then call the delegate variable as if it were a normal method. Here is an example: using System; public delegate void Simple(); public class Program { static int Main() { Simple msg = delegate() { Console.WriteLine("Welcome to the Wonderful World of C# Programming!"); }; msg(); return 0; } }
You can also create an anonymous method using an operator called lambda and represented by =>. From our example above, to use the lambda operator to create an anonymous method, omit the delegate keyword and follow the parentheses by the operator. Here is an example: using System; public delegate void Simple(); public class Program { static int Main() { Simple msg = () => { Console.WriteLine("Welcome to the Wonderful World of C# Programming!"); }; return 0; } } Once you have done this, you can call the delegate variable as a method. Here is an example: using System; public delegate void Simple(); public class Program { static int Main() { Simple msg = () => { Console.WriteLine("Welcome to the Wonderful World of C# Programming!"); }; msg(); return 0; } }
You can create a delegate that returns a value. When creating the delegate, specify the data type to the left side of the name of the delegate. When defining a method that would be associated with the delegate, remember that the method must return the same type of value. In the body of the method, use it as you see fit. Before exiting the method, make sure you appropriately return a value. To use the method, follow the same approach as above. This time, when calling the delegate variable, you should use the parentheses. Here is an example: using System; delegate double Doubler(); public class Exercise { public static double MultiplyBy2() { return 255 * 2; } } public class Program { static int Main() { Doubler By2 = Exercise.MultiplyBy2; Console.WriteLine("Number = {0}", By2()); return 0; } } This would produce: Number = 510 Press any key to continue . . . In the same way, you can create an anonymous method that implements the delegate. To do this, follow the same rule we defined earlier. For example, you can use the delegate keyword. Here is an example: using System; delegate double Doubler(); public class Program { static int Main() { Doubler By2 = delegate() { return 255 * 2; }; Console.WriteLine("Number = {0}", By2()); return 0; } } Or you can use the lambda operator: using System; delegate double Doubler(); public class Program { static int Main() { Doubler By2 = () => { return 255 * 2; }; Console.WriteLine("Number = {0}", By2()); return 0; } }
One of the characteristics that set delegates apart from C/C++ function pointers is that one delegate can be added to another using the + operation. This is referred to as composition. This is done by adding one delegate variable to another as in a = b + c. |
If you want to use a method that takes arguments and associate it to a delegate, when declaring the delegate, provide the necessary argument(s) in its parentheses. Here is an example of a delegate that takes two arguments (and returns a value): delegate double Doubler(double x); When defining the associated method, besides returning the same type of value if not void, make sure that the method takes the same number of arguments. Here is an example: public class Algebra { public static double MultiplyBy2(double a) { return a * 2; } }
To associate the method to the delegate, you can declare a variable for the delegate and assign the name of the method to it. Here is an example: using System; delegate double Doubler(double x); public class Algebra { public static double MultiplyBy2(double a) { return a * 2; } } public class Program { static int Main() { Doubler dbl = Algebra.MultiplyBy2; Console.WriteLine("Result = {0}", dbl); return 0; } } Notice that only the name of the method is passed to the delegate. To actually use the delegate, when calling it, add the parentheses to it and in the parentheses, provide a value for the argument(s). Here is an example: using System; delegate double Doubler(double x); public class Algebra { public static double MultiplyBy2(double a) { return a * 2; } } public class Program { static int Main() { Doubler dbl = Algebra.MultiplyBy2; Console.WriteLine("Result = {0}", dbl(248)); return 0; } } This would produce: Result = 496 Press any key to continue . . .
You can create an anonymous method for a delegate that takes one or more arguments. You can do this using the delegate keyword. In its parentheses, pass an argument that is the same type as the argument of the delegate. Then, in the body of the method, do what you judge necessary. When calling the variable of the delegate, use the same rules we have applied so far. Here is an example: using System; delegate double Doubler(double x); public class Program { static int Main() { Doubler dbl = delegate(double alpha) { return alpha * 2; }; Console.WriteLine("Result = {0}", dbl(248)); return 0; } } This technique of using the delegate keyword was introduced in C# 2.0 and has been updated with the lambda operator. Therefore, this was probably the last time we use it since we have been able to apply to different types of delegates. Instead of the delegate keyword, you can define an anonymous method using the lambda operator. In this case, in the parentheses of the lambda expression, enter the data type of the argument followed by its name. Here is an example: using System; delegate double Doubler(double x); public class Program { static int Main() { Doubler dbl = (double alpha) => { }; return 0; } } In the body of the anonymous method, use the argument as you see fit. Here is an example: using System; delegate double Doubler(double x); public class Program { static int Main() { Doubler dbl = (double alpha) => { return alpha * 2; }; return 0; } } After defining the method, you can call it like a normal method. Here is an example: using System; delegate double Doubler(double x); public class Program { static int Main() { Doubler dbl = (double alpha) => { return alpha * 2; }; Console.WriteLine("Result = {0}", dbl(248)); return 0; } } In our example, we specified the type of the argument. If you want, you can let the compiler figure out the type of argument. In this case, pass only the name of the argument and not its type. Here is an example: using System; delegate double Doubler(double x); public class Program { static int Main() { Doubler dbl = (alpha) => { return alpha * 2; }; Console.WriteLine("Result = {0}", dbl(248)); return 0; } }
A delegate can take more than one argument. To start, when declaring it, pass the desired number of arguments. If you will use a method to associate to the delegate, then create the method also. Here is an example: delegate double Addition(double x, double y); public class Algebra { public static double Plus(double a, double b) { return a + b; } } To use the delegate, follow the techniques we have applied so far and call the delegate as a method. Here is an example: using System; delegate double Addition(double x, double y); public class Algebra { public static double Plus(double a, double b) { return a + b; } } public class Exercise { static int Main() { Addition Operation = Algebra.Plus; Console.WriteLine("Result = {0}", Operation(52.04, 9.368)); return 0; } } This would produce: Result = 61.408 Press any key to continue . . . If you want to use a lambda expression to create an anonymous method, in its parentheses, pass the right number of arguments. In the body of the anonymous method, use the arguments ad you see fit. To use the delegate, call it as you would a normal method. Here is an example: using System; delegate double Addition(double x, double y); public class Exercise { static int Main() { Addition Operation = (x, y) => { return x + y; }; Console.WriteLine("Result = {0}", Operation(52.04, 9.368)); return 0; } }
Using delegates, one method can be indirectly passed as argument to another method. To proceed, first declare the necessary delegate. Here is a example of such a delegate: public delegate double Squared(double x); public class Circle { private double _radius; public double Radius { get { return _radius; } set { _radius = value; } } } A delegate can be passed as argument to a method. Such an argument would be used as if it were a method itself. This means that, when accessed in the body of the method, the name of the delegate must be accompanied by parentheses and if the delegate takes an argument or arguments, the argument(s) must be provided in the parentheses of the called delegate. Here is an example: public delegate double Squared(double x); public class Circle { private double _radius; public double Radius { get { return _radius; } set { _radius = value; } } public double Area(Squared sqd) { return sqd(_radius) * Math.PI; } } After declaring a delegate, remember to define a method that implements the needed behavior of that delegate. You can define the associated method in a class other than the one where the delegate would be used. Here is an example: using System; public class Exercise { public static double ValueTimesValue(double Value) { return Value * Value; } static int Main() { return 0; } } You can also define the method in the class where the delegate would be needed. Once the method that implements the delegate is known, you can use the delegate as you see fit. To do that, you can declare a variable of the type of that delegate and assign it to the variable. Here is an example: using System; public delegate double Squared(double x); public class Circle { private double _radius; public double Radius { get { return _radius; } set { _radius = value; } } public double Area(Squared sqd) { return sqd(_radius) * Math.PI; } } public class Exercise { public static double ValueTimesValue(double Value) { return Value * Value; } static int Main() { Squared Sq = ValueTimesValue; return 0; } } This declaration gives life to the delegate and can then be used as we have proceed with delegates so far. Here is an example: using System; public delegate double Squared(double x); public class Circle { private double _radius; public double Radius { get { return _radius; } set { _radius = value; } } public double Area(Squared sqd) { return sqd(_radius) * Math.PI; } } public class Exercise { public static double ValueTimesValue(double Value) { return Value * Value; } static int Main() { Squared Sqr = ValueTimesValue; Console.WriteLine("Circle Area: {0}\n", Sqr(24.68)); return 0; } } This would produce: Circle Area: 609.1024 Press any key to continue . . . In the same way, you can use a lambda expression to implement an anonymous method that would be associated with a delegate. Here is an example: using System; public delegate double Squared(double x); public class Circle { private double _radius; public double Radius { get { return _radius; } set { _radius = value; } } public double Area(Squared sqd) { return sqd(_radius) * Math.PI; } } public class Exercise { static int Main() { Squared Sqr = (a) => { return a * a; }; Console.WriteLine("Circle Area: {0}\n", Sqr(24.68)); return 0; } }
So far, we have learned how to create and use delegate of primitive types. We learned how to create a void delegate, how to create a delegate that returns a value, and how to create a delegate that takes one or more argument. Just as a reminder, here is an example: using System; delegate double Multiplication(); public class Cube { private double _side; public double Side { get { return _side; } set { _side = value; } } public Cube() { _side = 0; } public Cube(double s) { _side = s; } internal double Area() { return 6 * Side * Side; } internal double Volume() { return Side * Side * Side; } } public class Exercise { static int Main() { Cube SmallBox = new Cube(25.58); Multiplication AreaDefinition = SmallBox.Area; Multiplication VolDefinition = SmallBox.Volume; Console.WriteLine("Cube Characteristics"); Console.WriteLine("Side: {0}", SmallBox.Side); Console.WriteLine("Area: {0}", AreaDefinition); Console.WriteLine("Volume: {0}\n", VolDefinition); return 0; } } This would produce: Cube Characteristics Side: 25.58 Area: 3926.0184 Volume: 16737.925112
A delegate can be created to return a value that is of a class type. Of course you must know the class you want to use because the compiler would like to know the type of value that the delegate would return. You can use one of the many built-in classes of the .NET Framework or you can create your own class. When creating the delegate, specify the name of the class to its left as the returned type of value. Here is an example: delegate Person Creator(); public class Person { public string FirstName; public string LastName; } After doing this, you can create a method that implements the delegate. The method must return the same type of value as the delegate. Here is an example: using System; delegate Person Creator(); public class Person { public string FirstName; public string LastName; } public class Exercise { private static Person Create() { Person pers = new Person(); pers.FirstName = "Julius"; pers.LastName = "Krands"; return pers; } } To use the delegate, declare a variable for it and assign the method to it. Here is an example: using System; delegate Person Creator(); public class Person { public string FirstName; public string LastName; } public class Exercise { private static Person Create() { Person pers = new Person(); pers.FirstName = "Julius"; pers.LastName = "Krands"; return pers; } static int Main() { Creator crt = Create; return 0; } } You can then call use the variable as you see fit. Instead of explicitly creating a method that implements the delegate, you can create an anonymous method using a lambda expression. In the body of the anonymous method, make sure you return a value of the type of the delegate. Here is an example: using System; delegate Person Creator(); public class Person { public string FirstName; public string LastName; } public class Exercise { static int Main() { Creator Create = () => { var PersonalInformation = new Person(); PersonalInformation.FirstName = "Julius"; PersonalInformation.LastName = "Krands"; return PersonalInformation; }; Create(); return 0; } }
A delegate can be created to receive a class type as argument. When creating the delegate, in its parentheses, specify the class whose value it takes as argument. Here is an example: using System; delegate void Anchor(Person p); public class Person { public string FirstName; public string LastName; } To use the delegate, you can first create a method that implements the delegate, then declare a variable for the delegate and assign the method to it. If you prefer to create an anonymous method using a lambda expression, in the parentheses, enter a name for the argument and use that argument in the body of the method as you see fit. Here is an example: public class Exercise { static int Main() { Anchor personal = (individual) => { Console.WriteLine("=//= Personal Information =//="); Console.WriteLine("First Name: {0}", sample.FirstName); Console.WriteLine("Last Name: {0}", sample.LastName); }; return 0; } } You can then call the method as you see fit. Here is an example: using System; delegate Person Creator(); delegate void Anchor(Person p); public class Person { public string FirstName; public string LastName; } public class Exercise { static int Main() { var PersonalInformation = new Person(); Creator Create = () => { PersonalInformation.FirstName = "Julius"; PersonalInformation.LastName = "Krands"; return PersonalInformation; }; Anchor personal = (individual) => { Console.WriteLine("=//= Personal Information =//="); Console.WriteLine("First Name: {0}", individual.FirstName); Console.WriteLine("Last Name: {0}", individual.LastName); }; Create(); personal(PersonalInformation); return 0; } } This would produce: =//= Personal Information =//= First Name: Julius Last Name: Krands Press any key to continue . . . In the same way:
Except for the main class of your program (the class that contains the Main() method), every class is mostly meant to interact with other, either to request values and methods of the other classes or to provide other classes with some values or a behavior they need. When a class A requests a value or service from another class B, class A is referred to as a client of class B. This relationship is important not simply because it establishes a relationship between both classes but also because class B should be ready to provide the value or behavior that a client needs at a certain time. While a class B is asked to provide some values or methods to another class A, many things would happen. In fact, there is an order that things should follow. For example, during the lifetime of a program, that is, while a program is running, a class may be holding a value it can provide to its client but at another time, that value may not be available anymore, for any reason; nothing strange, this is just the ways it happens. Because different things can happen to a class B while a program is running, and because only class B would be aware of these, it must be able to signal to the other classes when there is a change. This is the basis of events: An event is an action that occurs on an object and affects it in a way that its clients must be made aware of. Events are mostly familiar to those who do graphical (GUI) programming as they are able to "visually" work on Windows controls and as they are able to access the objects on which actions are happening and the objects that must know when these actions occur. Still, because events are dealt with in C#, you should be aware of their functionality. Although events are mostly used in Windows controls programming, they can also be implemented in console applications.
An event is declared like a pseudo-variable but based on a delegate. Therefore, to declare an event, you must have a delegate that would implement it. Here is an example: using System; delegate void dlgSimple(); class Exercise { public static void Welcome() { Console.WriteLine("Welcome to the Wonderful World of C# Programming!"); } } To actually declare an event, you use the event keyword with the following formula: [attributes] [modifiers] event type declarator; [attributes] [modifiers] event type member-name {accessor-declarations}; The attributes factor can be a normal C# attribute. The modifier can be one or a combination of the following keywords: public, private, protected, internal, abstract, new, override, static, virtual, or extern. The event keyword is required. It is followed by the name of the delegate that specifies its behavior. If the event is declared in the main class, it should be made static. Like everything in a program, an event must have a name. This would allow the clients to know what (particular) event occurred. Here is an example: using System; delegate void dlgSimple(); class Exercise { public static event dlgSimple Simply; public static void Welcome() { Console.WriteLine("Welcome to the Wonderful World of C# Programming!"); } } After declaring the event, you must define a method that calls the event. Here is an example: using System; delegate void dlgSimple(); class Exercise { public static event dlgSimple Simply; public static void Welcome() { Console.WriteLine("Welcome to the Wonderful World of C# Programming!"); } public static void SayHello() { Simply(); } } When the event occurs, its delegate would be invoked. This specification is also referred to as hooking up an event. As the event occurs (or fires), the method that implements the delegate runs. This provides complete functionality for the event and makes the event ready to be used. Before using an event, you must combine it to the method that implements it. This can be done by passing the name of the method to the appropriate delegate, as we learned when studying delegates. You can then assign this variable to the event's name using the += operator. Once this is done, you can call the event. Here is an example: using System; delegate void dlgSimple(); class Exercise { public static event dlgSimple Simply; public static void Welcome() { Console.WriteLine("Welcome to the Wonderful World of C# Programming!"); } public static void SayHello() { Simply(); } static int Main() { Simply += new dlgSimple(Welcome); SayHello(); return 0; } } Instead of the += operator used when initializing the event, you can implement add and remove of the event class. Here is an example: using System; delegate void dlgSimple(); class Exercise { public event dlgSimple Simply { add { Simply += new dlgSimple(Welcome); } remove { Simply -= new dlgSimple(Welcome); } } public void Welcome() { Console.WriteLine("Welcome to the Wonderful World of C# Programming!"); } }
|
|
||
Previous | Copyright © 2008-2016, FunctionX, Inc. | Next |
|