Deep C# - Delegates
Written by Mike James   
Monday, 02 June 2025
Article Index
Deep C# - Delegates
The C# Approach
Delegate Patterns
Generic Delegates

The C# Approach

The overall C# approach to allowing functions to be first-class entities has developed over time as well. Initially delegates were used as a way of wrapping a function in an object in a way that is superficially similar to Java's approach but with some special advantages. C# delegates also acquired features that made them easier to use - anonymous methods and finally lambdas. However, it is important that you fully understand the original idea of delegates and how to use them, so let’s look at how it works and some of the more interesting ways that you can put it to work. The relationship of delegates to events is covered in the next chapter.

Delegate Basics

What is initially confusing is that to create a delegate you first have to create a type and then create an instance of the type. That is, a delegate is a user-defined reference type that encapsulates a method. Consider, for example, how to encapsulate the simple example method:

public int hello(int param1){
  MessageBox.Show("Hello delegate World"+param1.ToString());
  return(++param1);
}

All this does is display the current value of param1 and then return an incremented value.

First, we need to define a delegate type that matches its signature, including the return type:

delegate int HelloType(int param);

This delegate type defines the methods that it can encapsulate. Notice that it is only the function’s signature and return type that specifies the delegate type. The HelloType delegate can wrap any function that has the specified signature and return. 

Next, we have to create an instance of the type and supply it with the hello method to encapsulate:

HelloType HelloInst = new HelloType(hello);

If you prefer you can use the overloaded assignment operator:

HelloType HelloInst = hello;

to create an instance.

Now we can run the original hello method by calling it directly in the usual way:

int i = hello(2);

or by using the delegate’s invoke method:

int i = HelloInst.Invoke(2);

or by calling the delegate instance as if it was the hello method:

int i = HelloInst(2);

This last form is just a convenience as it implicitly uses the Invoke method.

Notice that the default use of the Invoke method makes the delegate instance look like a function object. That is HelloInst is an object but HelloInst(2) looks like a function call. 

Of course, there are a few slightly hidden details in these examples which are obvious to experts, but often confuse the beginner. The first is that the method being wrapped is still a method belonging to some object and not a "disembodied" function. When the delegate is used to wrap the method the method has to be accessible from wherever the delegate is being declared. In the example above there is the implicit assumption that all of the code is defined within the same class. 

A more elaborate and complete example would create the hello method within a new class:

public class Greetings
{
   public int hello(int param1)
  {
MessageBox.Show("Hello delegate World"+
param1.ToString());
return (++param1);   } }

and then within the class that wants to make use of the method you can make use of the delegate type to wrap the method instance:

delegate int HelloType(int param); 
private void button1_Click(object sender, EventArgs e)
{
  Greetings g = new Greetings();
  HelloType HelloInst = new HelloType(g.hello);
  int i = HelloInst(2);
}

Another subtle point is that Invoke uses the same thread to run the delegate and in this case you need to be aware of any potential “cross-threading” problems that might arise. This also means that the invocation is synchronous and the calling code will wait until the delegate returns. You can invoke the delegate asynchronously using a thread from the thread pool using BeginInvoke or you could create a thread manually to run the delegate.

To summarize:

To wrap a method belonging to an instance of a class you have to first define a new delegate type with a specific signature and return type, then you wrap the method in an instance of the delegate type. 



Last Updated ( Monday, 02 June 2025 )