Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

C# - Delegates 101 - A Practical Example

0.00/5 (No votes)
11 Apr 2010 1  
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
This will result in an object. That object can then be:
  • 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:

Episode 1 - Without delegates

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:

  1. A public delegate is declared, that will serve as the wrapper of the method that has to be invoked
  2. The MarketingDepartment will fill that wrapper with the method of its choice (SendBallpens or SendCoffeeCups), and pass the wrapper to AddressProvider
  3. 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 2 : Delegate telling what to do

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:

Episode 3 : Giving a choice

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!

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here