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

Delegates are C#'s original way of allowing you to work with functions as if they were first-class objects. The aim may be simple, but the need to define a type and then an instance of the type can be confusing. Find out more in this extract from my book, Deep C#: Dive Into Modern C#.

Deep C#

 Buy Now From Amazon

DeepCsharp360

 Chapter List

  1. Why C#?
    I Strong Typing & Type Safety
  2. Strong Typing
       Extract 
    Why Strong Typing
  3. Value & Reference
  4.    Extract Value And Reference
  5. Structs & Classes
       Extract
    Structs & Classes 
  6. Inheritance
      
    Extract
    Inheritance
  7. Interfaces & Multiple Inheritance
      
    Extract Interface
  8. Controlling Inheritance
    II Casting & Generics
  9. Casting - The Escape From Strong Typing
      
    Extract Casting I
  10. Generics
  11. Advanced Generics
  12. Anonymous & Dynamic
    Typing
    III Functions
  13. Delegates ***NEW!
  14. Multicast Delegates
  15. Anonymous Methods, Lambdas & Closures
    IV Async
  16. Threading, Tasks & Locking
  17. The Invoke Pattern
  18. Async Await
  19. The Parallel For
    V Data - LINQ, XML & Regular Expressions
  20. The LINQ Principle
  21. XML
  22. LINQ To XML
  23. Regular Expressions
    VI Unsafe & Interop
  24. Interop
  25. COM
  26. Custom Attributes
  27. Bit Manipulation
  28. Advanced Structs
  29. Pointers 

Extra Material

 

 

Delegates are at the core of a number of different .NET facilities, events in particular. It’s long been a truism that the way to get work done is to delegate, but what are C# delegates all about? First we have to understand the nature of the problem that delegates are designed to solve.

First-Class Functions

In many languages functions are treated in the same way as objects. In JavaScript, for example, functions are objects. This is often expressed by saying the functions are first-class objects or they are first-class functions. 

Why should this matter? The simple answer is that sometimes you want to pass a function as an argument to a method call. There are other things you might want to do with a first-class function, including having a reference to it or having an array of such functions, but if we concentrate on the most common usage, passing functions to methods, then we have the key idea. For example, suppose you have a sorting routine, you might want to pass in a function that determines what A>B means, i.e. return true if A is greater than B and false otherwise, where A and B are objects of some type. 

This seems like a reasonable thing to do, but notice that in C# and in other object-oriented languages there are no "disembodied" functions. All functions are methods that belong to some class or instance of a class. This make things a little more complicated because now you cannot simply create a function called myOrder and pass it into a method because myOrder has to be a method of some class or object.

You might think of defining something like:

class Compare{
 	public myOrder(){};
}

and now you could try to pass an instance of the object:

Compare myCompare = new Compare();
myData.Sort(myCompare.myOrder);

That is, you are trying to pass myCompare.myOrder to the Sort method. 

This is an approach that could be made to work, but C# is strongly typed and every parameter in a method has to have a type. What type is Compare.myOrder? It’s a method of a type and not a type in its own right and trying to make it a type will quickly become very messy. 

A different alternative is to demand that every time you want to pass a function you have to pass an object that has that function as a method. This is what Java does, for example. In this case we don't have a problem with types:

Compare myCompare = new Compare();
myData.Sort(myCompare);

However, within the Sort method the myOrder function has to be called as: 

myCompare.myOrder();

In other words, to pass a function you have to pass an entire object which wraps the function. Of course, the one advantage of this method is that, in principle, you could pass a whole set of functions in one go, but this doesn't make up for the inconvenience of the approach when you are trying to pass just one function. 

As any Java programmer will tell you, this approach is workable but very verbose. You have to define a class for every function you want to pass and create an instance to pass every time you want to pass it. It is the original method that Java used to implement event handling and over time new facilities such as anonymous classes and eventually lambdas have been added to the language to make this cumbersome method easier to use. 



Last Updated ( Monday, 02 June 2025 )