C# - Delegates 101 - A Practical Example






4.82/5 (97 votes)
A practical example not too simple, not too complex, to explain delegates
This article has completely been reviewed, thanks to many encouraging comments below.
Introduction
Delegates play a major role in C# (e.g. LINQ's lambda expressions), so it's a good idea to really understand them.
Luckily, you'll find a whole bunch of well written articles on CodeProject that explain delegates (see links at the end). But IMHO, most articles fail to include a good example. Either they are too simple or too complex.
In this article, I'll try to give a practical example, albeit not from the real coding world.
It's meant to give you a *feel* of how and when to use delegates.
Still, the code will execute!
Delegates Simplified Recap
All you C# buffs will excuse me if I give a quick recap of delegates, and oversimplify things while doing so.
First off, a delegate is a type, i.e. a class. It’s a special class (you'll see why in a sec), but still, it's just a class.
That means that like any other class, in order to be used, it must be:
- declared and
- instantiated
- invoked
These are the 3 main steps in the lifecycle of a delegate. I'll point them out in the code.
Episode 1 – Without Delegates: the MarketingDepartment and its Service Providers
Suppose you have a class, called MarketingDepartment
. It's job is to run advertising campaigns on new prospects (class CustomerAddress
).
If the budget is less then 10000, only Ballpens will be sent to the prospects. If we can afford more, we'll send coffee cups!
In order to do that, MarketingDepartment
has 3 different "service providers" : an AddressProvider
that will provide addresses, a BallpenCompany
that will send the ballpens, and a CoffeeCupCompany
that... well, you get the idea !
In an UML class diagram, it could look like this:

In code, we could write something like this:
class Program
{
static void Main(string[] args)
{
bool success = false;
MarketingDepartment MyDepartment = new MarketingDepartment();
success = MyDepartment.ExecuteNewCampaign(5000);
Console.WriteLine("The new marketing campaign has {0} !",
success == true ? "succeeded" : "failed");
}
}
public class CustomerAddress
{
//Properties of Customer Address (Name, Street, City, etc.)
}
The Program
class is the starting point. CustomerAddress
is the class we'll use to pass addresses of prospects.
The real shabang goes on in the MarketingDepartment
:
we'll fetch the adresses, and send those to the BallpenCompany
or the CoffeeCupCompany
, depending on the given budget.
public class MarketingDepartment
{
public bool ExecuteNewCampaign(decimal budget)
{
bool success = false;
AddressProvider MyAddressProvider = new AddressProvider();
List<CustomerAddress> ListOfAddresses =
MyAddressProvider.GetAddressesNewProspects();
if (budget < 10000)
{
BallpenCompany MyBallpenCompany = new BallpenCompany();
success = MyBallpenCompany.SendBallPens(ListOfAddresses);
}
else
{
CoffeeCupCompany MyCoffeeCupCompany = new CoffeeCupCompany();
success = MyCoffeeCupCompany.SendCoffeeCups(ListOfAddresses);
}
return success;
}
}
These are the service providers:
public class AddressProvider
{
public List<CustomerAddress> GetAddressesNewProspects()
{
List<CustomerAddress> ListOfAddresses = new List<CustomerAddress>();
//add addresses of prospects
return ListOfAddresses;
}
}
public class BallpenCompany
{
public bool SendBallPens(List<CustomerAddress> ListOfAddresses)
{
//for each CustomerAddress send ball pen
return true;
}
}
public class CoffeeCupCompany
{
public bool SendCoffeeCups(List<CustomerAddress> ListOfAddresses)
{
//for each CustomerAddress send coffee cup
return true;
}
}
Episode 2 – Enter the Delegate: Tell the AddressProvider How to Proceed!
The Marketing people, smart as they are, have an idea to speed things up! They say: "Hey, we don't want to waste time getting the addresses back from the AddressProvider
and then send them to the BallpenCompany
or the CoffeeCupCompany
. Instead, it would save time if the AddressProvider
knows immediately what to do with the addresses." />
In short, this is the strategy to follow:
- A public delegate is declared, that will serve as the wrapper of the method that has to be invoked
- The
MarketingDepartment
will fill that wrapper with the method of its choice (SendBallpens
orSendCoffeeCups
), and pass the wrapper toAddressProvider
- The
AddressProvider
will accept the wrapper, and invoke it, without even knowing what concrete method is being executed
Here's how it would look like in code (I have cut out the bits that didn't change)
// here is the DECLARATION of the delegate (Step 1)
// the delegate class name is "DoAfterGetAddresses"
// it must specify the signature of the methods it will represent :
// the return type (bool in this case, can be any type, or "void")
// and optionally the parameters (in this case : List<CustomerAddress>)
public delegate bool DoAfterGetAddresses(List<CustomerAddress> ListOfAddresses);
public class MarketingDepartment
{
public bool ExecuteNewCampaign(decimal budget)
{
bool success = false;
AddressProvider MyAddressProvider = new AddressProvider();
// here I will declare a delegate object of the delegate type above
// I will not instantiate it yet, because that depends on the budget
DoAfterGetAddresses ToDoAfterAddresses;
if (budget < 10000)
{
BallpenCompany MyBallpenCompany = new BallpenCompany();
// here I'll instantiate the delegate object (Step 2)
// I need to assign a method with the same signature as declared
// Also notice that I don't need to give the parameter yet
ToDoAfterAddresses = MyBallpenCompany.SendBallPens;
}
else
{
CoffeeCupCompany MyCoffeeCupCompany = new CoffeeCupCompany();
//same here
ToDoAfterAddresses = MyCoffeeCupCompany.SendCoffeeCups;
}
// it's now time to let the AddressProvider handle the campaign
// note how we pass the delegate instance as a parameter
success = MyAddressProvider.HandleCampaign(ToDoAfterAddresses);
return success;
}
}
public class AddressProvider
{
//here's the method that accepts the delegate object as parameter
public bool HandleCampaign(DoAfterGetAddresses ToDoAfterAddresses)
{
bool success = false;
//get the addresses first
List<CustomerAddress> ListOfAddresses = GetAddressesNewProspects();
//now invoke the delegate (Step 3)
//at this stage, the ListOfAddresses is needed to pass as argument
success = ToDoAfterAddresses(ListOfAddresses);
// this means that the AddressProvider does NOT know what method
// exactly has been called : MyBallpenCompany.SendBallPens
// or MyCoffeeCupCompany.SendCoffeeCups
// that was the decision of the MarketingDepartment
// Furthermore, the signature tells me that the
// delegated method will return a boolean,
// that I can return that to the MarketingDepartment
return success;
}
public List<CustomerAddress> GetAddressesNewProspects()
{
....
}
}
Conclusion
A delegate turns out to be a sort of an interface of a method of an object -- ANY method of ANY object that meets its signature.
The delegate object can then be passed around as a parameter, and invoked by the receiving object.
In UML, I don't know (yet) how a delegate is diagrammed, but this is my best shot (better suggestions are welcome!)

Episode 3 – Another Scenario: Delegates that Tell the MarketingDepartment How to Proceed!
Another scenario would be that the AddressProvider
has a connection with a BallpenCompany
and a CoffeeCupCompany
, as the UML class diagram shows.
Instead of exposing those companies to the MarketingDepartment
, the AdressProvider
makes 2 delegates available: one for sending ballpens, another for sending coffee cups.
Here's the UML:

And here's the code. Tip: have a look first at the AddressProvider
!
public class MarketingDepartment
{
public bool ExecuteNewCampaign(decimal budget)
{
bool success = false;
AddressProvider MyAddressProvider = new AddressProvider();
// getting the addresses
List<CustomerAddress> ListOfAddresses =
MyAddressProvider.GetAddressesNewProspects();
if (budget < 10000)
{
//step 3
success = MyAddressProvider.MySendBallPens(ListOfAddresses);
}
else
{
//step 3
success = MyAddressProvider.MySendCoffeeCups(ListOfAddresses);
}
return success;
}
}
//declaration of 2 delegates (step 1)
public delegate bool SendBallPens(List<CustomerAddress>ListOfAddresses);
public delegate bool SendCoffeeCups(List<CustomerAddress>ListOfAddresses);
public class AddressProvider
{
// I'll keep the Ballpen & Coffeecup as private fields
private BallpenCompany MyBallpenCompany;
private CoffeeCupCompany MyCoffeeCupCompany;
// I'll have the delegate objects as fields available
public SendBallPens MySendBallPens;
public SendCoffeeCups MySendCoffeeCups;
// in the constructor, I'll instantiate
// the Ballpen & Coffeecup companies
// and also the delegate objects (step 2)
public AddressProvider()
{
MyBallpenCompany = new BallpenCompany();
MyCoffeeCupCompany = new CoffeeCupCompany();
MySendBallPens = MyBallpenCompany.SendBallPens;
MySendCoffeeCups = MyCoffeeCupCompany.SendCoffeeCups;
}
public List<CustomerAddress> GetAddressesNewProspects()
{
....
}
}
Conclusion
Delegates are a cornerstone for a significant portion of the C# language, especially the event-framework.
Yet, they have a right on their own to be used in code.
So, it's worth spending some time trying to understand them as completely as possible.
Although there are many well-written articles available (see links below), most of them in my humble opinion lack a practical example that is neither too simple nor too complex.
This article tried to fill that gap. I hope it succeeded somewhat in achieving that goal.
Links
These are articles I learned a lot from. Some of them are even fun to read!