Delegates C# Help

Delegates exist for situations in which you want to pass methods around to other methods. To see what that means, consider this line of code:

int i = int.Parse{’99’);

You are so used to passing data to methods as parameters, as in this example, that you don’t consciously think about it, and for this reason the idea of passing methods around instead of data might sound a little strange. However, there are cases in which you have a method that does something, and rather than operating on data, the method might need to do something that involves invoking another method. To complicate things further, you do not know at compile time what this second method is. That information is available only at runtime and hence will need to be passed in as a parameter to the first method. That might sound confusing but should become clearer with a couple of examples.

  1. Starting threads – It is possible in C# to tell the computer to start some new sequence of execution in parallel with what it is currently doing. Such a sequence is known as a thread, and
    starting one up is done using the Start () method on an instance of one of the base classes, system, Threading. Thread. If you tell the computer to start a new sequence of execution, you have to tell it where to start that sequence. You have to supply it with the details of a method in which execution can start. In other words, the constructor of the Thread class takes a parameter that defines the method to be invoked by the thread.
  2.  Generic library classes – Many libraries contain code to perform various standard tasks. It is usually possible for these libraries to be self-contained, in the sense that you know when you write to the library exactly how the task must be performed. However, sometimes the task contains some sub task, which only the individual client code that uses the library knows how to perform. For example, say that you want to write a class that takes an array of objects and sorts them into ascending order. Part of the sorting process involves repeatedly taking two of the objects in the array and comparing them in order to see which one should come first. If you want to make the class capable of sorting arrays of any object, there is no way that it can tell in advance how to do this comparison. The client code that hands your class the array of objects will also have to tell your class how to do this comparison for the particular objects it wants sorted. The client code will have +0 pass your class details of an appropriate method that can be called and does the comparison.
  3.  Events – The general idea here is that often you have code that needs to be informed when some event takes place. GUI programming is full of situations like this. When the event is raised, the runtime will need to know what method should be executed. This is done by passing the method that handles the event as a parameter to a delegate. This is discussed later in the chapter.

In C and C++, you can just take the address of a function and pass  this as a parameter. There’s no type safety with <2~You can pass  any function to a method where a function pointer is  required. Unfortunately, this direct approach not only causes some problems with type safety but also neglects the fact that when you are doing object-oriented programming, methods rarely exist in isolation, but usually need to be associated with a class instance before they can be called. As a result of these problems, the .NET Framework does not syntactically permit this direct approach. Instead, if you want to pass methods around, you have to wrap’up the details of the method in a new kind of object, a delegate. Delegates quite simply are a special type of object – special in the sense that, whereas all the objects defined up to now contain data, a delegate contains the address of a method.

Declaring Delegates in C#

When you want to use a class in C#, you do so in two stages. First, you need to define the class – that is, you need to tell the compiler what fields and methods make up the class. Then (unIess you are using only static methods), you instantiate an object of that class. With delegates it is the same thing. You have to start off by defining the delegates you want to use. In the case of delegates, defining them means telling the compiler what kind of method a delegate of that type will represent. Then, you have to create one or more instances of that delegate. Behind the scenes, the compiler creates a class that represents the delegate.

The syntax for defining delegates looks like this:

delegate void IntMethodlnv6ker(int x);

In this case, you have defined a delegate called IntMethodlnvoker, and you have indicated that each instance of this delegate can hold a reference to a method that takes one int parameter and returns void. The crucial point to understand about delegates is that they are type-safe. When you define the delegate, you have to give full details of the signature and the return type of the method that it is going to represent.

One good way of understanding delegates is by thinking of a delegate as something that gives a name to a method signature and the return type.

Suppose that you wanted to define a delegate called TwoLongsOp that will represent a method that takes two longs as its parameters and returns a double. You could do it like this:

 delegate double TwoLongsOp(long first, long second);

Or, to define a delegate that will represent a method that takes no parameters and returns a string, you might write this:

delegate string GetAString();

The syntax is similar to that for a method definition, except that there is no method body and the definition is prefixed with the keyword delegate. Because what you are doing here is basically defining a new class, you can define a delegate in any of the same places that you would define a class – that is to say either inside another class or outside of any class and in a namespace as a top-level object. Depending on how visible you w.ant your definition to be, you can apply any of the normal access modifiers to delegate definitions – public, private, protected, and so on:

public delegate string GetAString();

We really mean what we say when we describe defining a delegate as defining a new class. Delegates are implemented as classes derived from the class System. Multicast Delegate, which is derived from the base class, System. Delegate. The C# compiler is aware of this class and uses its delegate syntax to shield you from the details of the operation of this class. This is another good example of how C# works in conjunction with the base classes to make programming as easy as possible.

After you have defined a delegate, you can create an instance of it so that you can use it to store details of a particular method.:

There is an unfortunate problem with terminology here. With classes there are two distinct terms – class, which indicates the broader definition, and object, which means an instance of the class. Unfortunately with delegates)here is only the one term. When you create an instance of a delegate, what you have created is also referred to as a delegate. You need to be aware of the context to know which meaning we are using when we talk about delegates.

Using Delegates In C#

The following code snippet demonstrates the use of a delegate. It is a rather long-winded way of calling the ToString () method on an int:

static void Main()
{
int x = 40;
GetAString firstStringMethod new GetAString(x.ToString);
Console.WriteLine(“String is {O}”, firstStringMethod());
II with firstStringMethod initialized to x.ToString(),
II the above statement is equivalent to saying
II Console.WriteLine(“String is (O)”, x.ToString{»;

In this code, you instantiate a delegate of type GetAString, and you initialize it so it refers to the ToString () method of the integer variable x. Delegates in C# always syntactically take a one-parameter constructor, the parameter being the method to which the delegate will refer. This method must match the signature with which you originally defined the delegate. So in this case, you would get a compilation error if you tried to initialize the variable firstStringMethod with any method that did not take any parameters and return a string. Notice that, because int . ToStrin\7 () is an instance method (as opposed to a static one), you need to specify the instance (x) as well as the name of the method to initialize the delegate properly.

The next line actually uses the delegate to display the string. In any code, supplying the name of a delegate instance, followed by brackets containing any parameters, has exactly the same effect as calling the method wrapped by the delegate. Hence, in the preceding code snippet, the Console. WriteLine ( ) statement is completely equivalent to the commented-out line.

In fact, supplying brackets to the delegate instance is the same as invoking the Invoke () method of the delegate class. Because firstStringMethod is a variable of a delegate type, the C# compiler replaces firstStringMethod () with firstStringMethod. Invoke ():

firstStringMethod{) ;
firstStringMethod.lnvoke();

For less typing, at every place where a delegate instance is needed, you can just pass the name of the address. This is known by the term delegate inference. This C# feature works as long as the compiler can resolve the delegate instance to a specific type. The example initialized the variable firstStringMethod of type GetAString with a new instance of the delegate GetAString:

GetAString firstStringMethod = new GetAString{x.ToString);

You can write the same just by passing the method name with the variable x to the variable firstStringMethod:

GetAString firstStringMethod = x.ToString;

The code that is created by the C# compiler is the same. The compiler detects that a delegate type is required with firstStringMethod, so it creates an instance of the delegate type GetAStrring and passes the address of the method with the object x to the constructor.

Be aware that you can’t type the ( and) as x. ToString () and pass it to the delegate variable. Thiswould, be an invocation of the method. Theinvocation of x. ToString () returns a string object that can’tbe assigned to the delegate variable, You can only assign tile address of a method to the delegate variable.

Delegate inference can be used any place a delegate instance is required. Delegate inference can also be used with events because events are based on delegates

One feature of delegates is that they are type-safe to the extent that they ensure the signature of the method being called is correct. However, interestingly, they do not care what type of object the method is being called against or even whether the method is a static method or an instance method.

An instance of a given delegate can refer to any instance of static method on any object of any type, provided that the signature of the method matches the signature , of the delegate.

To demonstrate this,the following example expands the previous code snippet so that it uses the firstStringMethod delegate to call a couple of other methods on another object- an instance method and a staticmethod. For this,you use the Currency struct,which is defined as follows.The Currency struct has its own overload of ToString () and a static method with the same signature to GetCurrencyUnit ().This way the same delegate variable can be used to invoke these methods.

Img

Now you can use your GetAString instance as follows:

This code shows how you can call a method via a delegate and subsequently reassign the delegate to refer to different methods on different instances of classes, even static methods or methods against instances of different types of class, provided that the signature of each method matches the delegate definition.

When you run the application, you get the output from the different methods that_are referenced by the delegate:

String is 40
String,is $34.50
String*is Dollar

However, you still haven’t seen the process of actually passing a delegate to another method. Nor have you actually-achieved anything particularly useful yet. It is possible to call the ToString () method of int and Currency objects in a much more straightforward way than using delegates! Unfortunately, the nature of delegates requires a fairly complex example before you can really appreciate their usefulness. The next section presents two delegate examples. The first one simply uses delegates to call a couple of different operations. It illustrates how to pass delegates to methods and how you can use arrays of delegates -‘although arguably it still doesn’t do much that you couldn’t do a lot more simply without delegates. Then. a second, much more complex example of a Bubble Sorter class is presented, which implements a method to sort out arrays of objects into increasing order. This class would be difficult to write without delegates.

 Simple Delegate Example

This example defines a Math Operations class that has it couple of static methods to perform two operations on doubles. Then you use delegates to call up these methods. The math class looks like this:

You call up these methods like this

private delegate string GetAString();
,static void MainO
C’
int’x = 40;
GetASt~ng firstStringMethod = x.ToString;
Console.WriteLine(‘String is {O}’, firstStringMethod());
Currency balance = new Currency(34, 50);
II firstStringMethod references an instance method
firstStringMethod = balance.ToString;
Console. WriteLine (‘ String is {O}’, firstStringMethod () ); . .\
II firstStringMethod references a static method
firstStringMethod = new GetAString(Currency.GetCUrrencyUnit);
Console.WriteLine(‘String is {O}’, firstStringMethod());

In this code, you instantiate an array of DoubleOp delegates (remember that once you have defined a delegate class, you can basically instantiate instances just like you can with normal classes, so putting some into an array is no problem). Each element of the array gets initialized to refer to a different operation implemented by the Math Operations class. Then, you loop through the array, applying each operation to three different values. This illustrates one way of using delegates – that you can group methods together into an array using them, so that you can call several methods in a loop.

The key lines in this code are the ones in which you actually pass each delegate to the ProcessAndDlsplayNumber () method, for example:

ProcessAndDisplayNumber(operations [i], 2.0);

Here, you are passing in the name of a delegate but without any parameters. Given that operations [i] is a delegate, syntactically,

  1.  operations [i] means the delegate (that is, the.method represented by the delegate).
  2.  operations [i] (2.0) means actually call this method, passing in the value in parentheses.

The ProcessAndDisplayNumber () method is defined to take a delegate as its first parameter:

 static void ProcessAndDisplayNumber(DoubleOp action, double value)

Then, when in this method, you call:

double result = action(value);

This actually causes the method that is wrapped up by the action delegate instance to be called and its return result stored in Result.

Running this example gives you the following:

SimpleDelegate
Using operations[O]:
value is 2, result of operation is 4
Value is 7.94, result of operation is 15.88
Value is 1.414, result of operation is 2.828
Using operations [1] :
Value is 2, result of operation is 4
Value is 7.94, result of operation is 63.0436
Value is 1.414, result of operation is 1.999396

Bubble Sorter Example

You are now ready for an example that will show delegates working in a situation in which they are very useful. You are going to write a class called BubbleSorter. This class implements a static method, Sort ( i,which takes as its first parameter an array of objects, and rearranges this array into ascending order. For example, if you were to pass it this array of ints, {O, 5, 6, 2, 1}, it would rearrange this array into {O, 1, 2, 5, 6} .

The bubble-sorting algorithm is a well-known and very simple way of sorting numbers. It is best suited to small sets of numbers, because for larger sets of numbers (more than about 10) far more efficient algorithms are available). It works by repeatedly looping through the array, comparing each pair of numbers and, if necessary, swapping them, so that the largest numbers progressively move to the end of the array. For sorting ints, a method to do a bubble sort might look like this:

This is all very well for ints, but you want your Sort () method to be able to sort any object. In other words, if some client code hands you an array of Currency structs or any other class or struct that it may have defined, you need to be able to sort the array. This presents a problem with the line if (sortArray !j ]<sortArray! i] ) in the preceding code, because that requires you to compare two objects on the array to see which one is greater. You can do that for ints, but how are you to do it for some new class that is unknown or undecided until runtime? The answer is the client code that knows about the class will have to pass in a delegate wrapping a method that will do the comparison.

You define the delegate like this:

delegate bool Comparison(object x, object y);

And you give your Sort method this signature:

static public void Sort(object!] sortArray, Comparison comparison)

The documentation for this method states that comparison must refer to a static method that takes two arguments, and returns true if the value of the second argument is greater than (that is, should come later in the array than) the first one.

Now you are all set. Here is the definition for the BubbleSorter class:

To use this class, you need to define some other class, which you can use to set up an array that needs sorting. For this example, assume that the Mortimer Phones mobile phone company has a list of employees and wants thern.serted according to salary. The employees are each represented by an instance of a class, Employee, which looks like this:

Notice that in order to match the signature of the Comparison delegate, you had to define Compare Salary in this class as taking two object references, rather than Employee references, as parameters. This means that you had to cast the parameters into Employee references in order to perform the comparison.

Instead of using objects as parameters here, strong typi~g generics can also be used.

Now you are ready to write some client code to request a sort:

using System;
Employee[] employees
(
; new Employee(‘Bugs Bunny’, 20000),
new Employee(‘Elmer Fudd’, 10000),
new Employee(‘Daffy Duck’, 25000),
new Employee(‘Wiley Coyote’, (decimal)1000000.38),
new Employee(‘Foghorn Leghorn’, 23000),
new Employee(‘RoadRunper’, SOOOO)};
namespace Wrox.ProCSharp.Delegates
(
delegate bool Comparison(object x, object y).;
c.iie.ss Program
(
static void Main()
–  (
BubbleSorter.Sort(employees, Employee.CompareSalary);
foreach (var employee in emplo’ es)
( .
Console.WriteLine(employee)

Running this code shows that the Employees are correctly sorted according to salary:

BubbleSorter
Elmer Fudd, $10,000.00
Bugs Bunny, $20,000.00

Foghorn Leghorn, $23,000.00
Daffy Duck, $25,000.00
RoadRunner, $50,000.00
Wiley Coyote, $1,000,000.38

Multicast Delegates

So far, each of the delegates you have used wraps just one single method call. Calling .the delegate amounts to calling that method. If you want to call more than one method, you need to make an explicit call through a delegate more than once. However, it is possible for a delegate to wrap more than one . method. Such a delegate is known as a multicast delegate. If a multicast delegate is called, it will successively call each method in order. For this to make sense, the delegate signature should return a void; otherwise, you would only get the result of the last method that is invoked by the delegate.

Consider the following code, which is adapted from the SimpleDelegate example. Although the syntax is the same as before, it is actually a multicast delegate, Operations, that gets instantiated

In the earlier example, you wanted to store references to two methods, so you instantiated an array of delegates. Here, you simply add both operations into the same multicast delegate. Multicast delegates recognize the operators + and +=. Alternatively, you can also expand the last two lines of the preceding code, as in this snippet:

Multicast delegates also recognize the operators – and -= to remove method calls from the delegate.

In terms of what’s going on under the hood, a multicast delegate is a class derived from System .Multicast:Delegate, which in turn is derived from System. Delegate. System . Multicast Delegate, and has additional members to allow chaining of method calls together into a list.

To illustrate the use of multicast delegates, the following code recasts the SimpleDelegate example into a new example, Mul ticastDelegate. Because you now need the delegate to refer to methods that return void, you have to rewrite the methods in the MathOperations class, so they display their results instead of returning them:

Console.WriteLine();
Console.WriteLine(“ProcessAndDisplayNumber called with value
valueToProcess);
action (valueToProcess) ;
{D}” ,
To accommodate this change, you also have to rewrite ProcessAndDisplayNumber:
statics:

Now you can try out your multicast delegate like this:

Now, each time ProcessAndDisplayNumber is called, it will display a message to say that it has been called.Then the following statement will cause each of the method calls in the action delegate instance to be called in succession:

action(value);

Running this code produces this result:

MulticastDelegate
ProcessAndDisplayNumber called with value 2
Multiplying by 4> 2 gives 4
Squaring: 2 give~ 4
ProcessAndDisplayNumber called with value 7.94
Multiplying by 2:’7.94 gives 15.88
Squaring: 7.94 gives 63.D436
ProcessAndDisplayNumber called with value 1.414
Multiplying by 2: 1.414 gives 2.828
Squaring: 1.414 gives 1.999396

If you are using multicast delegates, you should be aware that the order in which methods chained to the same delegate will be called is formally undefined. You should, therefore, avoid writing code that relies on such methods being called in any particular order.

Invoking multiple methods by one delegate might cause an even bigger problem. The multicast delegate contains a collection of delegates to invoke one after the other. If one of the methods invoked by a delegate throws an exception, the complete iteration stops. Have a look at the following Mul ticastlteration example. Here, a simple delegate named DemoDelegate that returns void without arguments is defined. This delegate is meant to invoke the methods One () and Two () that fulfill the parameter and retum type requirements of the delegate. Be aware that method One () throws an exception.

In the Main () method, delegate dl is created to reference method One ( ); next, the address of method Two () is added to the same delegate. dl is invoked to call both methods. The exception is caught in a try/catch block.

Only the first method is invoked by the delegate. Because the first method throws an exception, iterating the delegates stops here and method Two () is never invoked. The result might differ because the order of calling the methods is not defined.

One
Exception Caught

In such a scenario, you can avoid the problem by iterating the list on your own. The Delegate class defines the method GetlnvocationList () that returns an array of Delegate objects. You can now use this delegate to invoke the methods associated with them directly, catch exceptions, and continue with the next iteration:

When you run the application with the code changes, you can see that the iteration continues with the next method after the exception is caught:

One
Exception caught
Two

  Anonymous Methods

Up to this point, a method must already exist in order for the delegate to work (that is, the delegate is defined with the same signature as the methods) it will be used with). However, there is another way to use delegates – with anonymous methods. An anonymous method is a block of code that is used as the parameter for the delegate.

The syntax for defining a delegate with an anonymous method doesn’t change. It’s when the delegate is instantiated that things change. The following is a very simple console application that shows how using an anonymous method can work:

The delegate DelegateTest is defined inside the class Program. It takes a single string parameter. Where things become different is in the Main method. When anonDel is defined, instead of passing in a known method name, a simple block of code is used, prefixed by the delegate keyword, followed by a parameter:

I

As you can see, the block of code uses a method-level string variable, mid, which is defined outside of the anonymous method and adds it to the parameter that was passed in. The code then returns the string value. When the delegate is called, a string is passed in as the parameter and the returned string is output to the console.

The benefit of anonymous methods is to reduce the code you have to write. You don’t have to define a method just to use it with a delegate. This becomes very evident when defining the delegate for an event. (Events are discussed later in this chapter.) This can help reduce the complexity of code, especially where there are several events defined. With anonymous methods, the code does not perform faster. The compiler still defines a method; the method just has an automatically assigned name that you don’t need to know.

Acouple of rules must be followed when using anonymous methods. You can’t have a jump statement (br!lflk, goto, or continue) in an anonymous method that has a target outside of the anonymous method. The reverse is also true – a jump statement outside the anonymous method cannot have a target inside the anonymous method.

Unsafe code cannot be accessed inside an anonymous method. Also, ref and out parameters that are used outside of the anonymous method cannot be accessed. Other variables defined outside of the anonymous method can be used.

If you have to write the same functionality more than once, don’t use anonymous methods. In this case, instead bf duplicating the code, writing a named method is the preferred way. You only have to write it once and reference it by its name.

Lambda Expressions

C# 3.0 offers a new syntax for anonymous methods: Lambda expressions. Lambda expressions can be used with delegate types. The previous example using anonymous methods is changed to use a Lambda expression:

The left side of the Lambda operator => lists the parameters needed with the anonymous method. There are several ways to write this. For example, if a string parameter is needed as the delegate type defined in the sample code, one way to write this is by defining the type and variable name inside brackets:

(string param)

With Lambda expressions there’s no need to add the variable type to the declaration because the compiler knows about the type:

(param)

If there’s only one parameter, the brackets can be removed:

param

The right side of the Lambda expression lists the implementation. With the sample program the implementation was surrounded by curly brackets similar to the anonymous method earlier:

If the implementation consists of just a single line, you can also remove the curly brackets and the return statement because this is filled automatically by the compiler.

For example, with the following delegate that requires an int parameter and returns a beel:

public delegate bool Predicate(int obj)

you can declare a variable of the delegate and assign a Lambda expression. With the Lambda expression here, on the left side the variable x is defined. This variable is automatically of type int because this is as it is defined with the delegate. The implementation returns the Boolean result of comparing x > 5. If x is
larger than 5, true is returned, otherwise false.

Predicate pl = x => x > 5;

Youcan pass this Lambda expression to a method that requires a Predicate parameter.

list.FindAll(x => x > 5);

The same Lambda expression is shown here, without using variable type inference by defining the variable x of type int, and also adding the return statement to the implementation:

list.FindAll(int x) => ( return x > 5: }):

Using the older syntax, the same functionality is written by using an anonymous method:

list.FindAll(delegate(int x) ( return x > 5; });

With all these different variants, the C# compiler always creates the same It code.

Changing the SimpleDelegate sample shown earlier, you can eliminate the class MathOperations by using Lambda expressions. The Main () method would then look like this:

Running this version will give you the same results as the previous example. The advantage is that it eliminated a class.

Lambda expressions can be used any place where the type is a delegate. Another use of Lambda expressions is when the type is Expression or Expression<T>. Here the compiler creates an expression
tree. 

Posted on October 28, 2015 in Delegates and Events

Share the Story

Back to Top