Click here to Skip to main content
15,879,050 members
Articles / Programming Languages / C#

A Beginner's Tutorial on Basics of Delegates, Anonymous Functions and Lambda Expressions in C#

Rate me:
Please Sign up or sign in to vote.
4.86/5 (63 votes)
7 Dec 2012CPOL6 min read 86.9K   859   143   25
This article discusses delegates and how to write delegate handlers using functions, anonymous functions and Lambda expressions.

Introduction

In this article, you will learn about delegates and how to write delegate handlers using functions, anonymous functions and Lambda expressions. This article is written from a beginner's perspective and contains very introductory material on the related topics.

Background

Many a times, we need one part/object of our application to do something when some other part/object has been changed. One way to achieve this is by having an object poll continuously to another object and act whenever the other objects state is changed. Now this approach is not elegant, it involves too much of CPU usage. Also, there will be some time interval between 2 consecutive poll requests and if the other objects state was changed during this period, then we will get to know it later, i.e., delayed information.

Now, the way this problem is solved is called the Observer Pattern. Here, the object which wants to listen to the state change can subscribe to the object whose state will be changed. If we need to put this mechanism in a C# application, then we need to take care of both aspects of this pattern. One is sending the state change from an object to the listener(all the listeners) and receiving the state change of the object.

Delegates is the C# way of implementing the first part, i.e., keeping a track of all the listeners and sending them the notification when any state is changed. Anonymous methods and Lambda expressions come on the other side, i.e., handling the response coming from a delegate.

Using the Code

Let us try to implement a simple application with a class called BatteryLevel to understand these topics in action. This class will keep track of the current battery level of a device. Other classes can subscribe to a delegate provided by this class to listen to battery level change. Let us look at this class without any delegates introduced.

C#
class BatteryLevel
{
    int currentBatteryLevel;

    public int CurrentBatteryLevel
    {
        get
        {
            return currentBatteryLevel;
        }
        set
        {
            // Some process will call this setter to set the battery level
            currentBatteryLevel = value;
        }
    }
}

To implement delegates and its handlers, there are mainly four steps involved:

  1. Declaring the delegate
  2. Creating the delegate
  3. Hooking the delegate with handler functions
  4. Invoking the delegates

Now before adding a delegate to this class, let's get some basics clear. Delegates are types which we can define. The definition will declare the delegate and specify the method signature that this delegate can hold and call. Typical delegate declaration will look like:

[Access Modifier] delegate [Return type] [DELEGATE_NAME]([Function arguments]);

So to declare a delegate for our class, let's say we want the handler functions to return void and accept an integer value indicating the new battery level. The declaration will look like:

C#
// This is the delegate type, this will specify the name of the delegate
// and the function signature of the function that this delegate can call
public delegate void BatteryLevelBroadcaster(int batteryLevel);

Delegates can hold reference to a number of methods and when a delegate is invoked, it will call all the methods one by one sequentially. C++ programmers can think of delegates as a list of type safe function pointers.

Now we have seen the first part of our four step process. Now if we move on to the second part, i.e., creating the delegate, we simply need create a type of the delegate and assign some handler functions to it. If no handlers are associated with the delegate object, it will be null. So let's create a delegate type first.

C#
// This is the instance of our delegate type which will hold
// list of functions to call too
public BatteryLevelBroadcaster batteryLevelBroadcaster;

Now we have seen the second part of our 4 step process. Now if we move on to the fourth part, i.e., invoking the delegate. The typical way to call all the functions associated with this delegate would be to call the delegate like a function.

C#
//let's check whether someone has registered for listening or not
if (batteryLevelBroadcaster != null)
{
    // Let's call all the functions with new battery level value
    batteryLevelBroadcaster(currentBatteryLevel);
}

So now the BatteryLevel class definition with the delegate will look like:

C#
class BatteryLevel
{
    int currentBatteryLevel;

    // This is the delegate type, this will specify the name of the delegate
    // and the function signature of the function that this delegate can call
    public delegate void BatteryLevelBroadcaster(int batteryLevel);

    // This is the instance of our delegate type which will hold
    // list of functions to call too
    public BatteryLevelBroadcaster batteryLevelBroadcaster;

    public int CurrentBatteryLevel
    {
        get
        {
            return currentBatteryLevel;
        }
        set
        {
            // Some process will call this setter to set the battery level
            currentBatteryLevel = value;

            //let's check whether someone has registered for listening or not
            if (batteryLevelBroadcaster != null)
            {
                // Let's call all the functions with new battery level value
                batteryLevelBroadcaster(currentBatteryLevel);
            }
        }
    }
}

Now we have seen the invoker objects part of implementing delegates, i.e., declaring, creating and invoking a delegate. Now let us see how the handing part can be written, i.e., hooking the functions to the delegates and having the handler function's body.

To hook a function to the delegate, we simply need to create the delegate type with the function name passed in the constructor. We can then assign this delegate type to the delegate exposed by the class.

static void Main(string[] args)
{
    // let's say we have a module that notifies the user with low battery
    // here, we are emulating it.
    BatteryLevel batteryLevel = new BatteryLevel();

    // Let's subscribe to the battery level delegate to know the current level
    batteryLevel.batteryLevelBroadcaster += 
           new BatteryLevel.BatteryLevelBroadcaster(BatteryLevelIndicator);
    
    // Now let us simulate the hardware function that will set the battery level
    batteryLevel.CurrentBatteryLevel = 35;
    batteryLevel.CurrentBatteryLevel = 30;
    batteryLevel.CurrentBatteryLevel = 25;
    batteryLevel.CurrentBatteryLevel = 20;
    batteryLevel.CurrentBatteryLevel = 15;
    // Once the above code is run, for each updation, we should get the
    // message written in our delegate function
}

// This is the function that will let the user know the current battery level
public static void BatteryLevelIndicator(int newValue)
{
    Console.WriteLine("New battery level is: {0}", newValue);
}

The above code simply creates a function and then attach that function to the delegate exposed by the class as the handler function. The function signature matches the delegate signature, otherwise the code would not compile.

We are also setting the value of battery level to test the application. Whenever we call set, our handler function will be invoked and it will print the message on the console.

Note: We have used += to assign the delegate because we need our function to add to the list of functions already added to this delegate. If we simply use = sign, it will wipe off the list of existing functions and have this function as the only function associated with the delegate.

So we have seen the 3rd part of our four step process, i.e., hooking up the handler functions with the delegates. When we run the application, we can see the handler function getting called via the delegate.

Anonymous Functions

Anonymous functions are the functions without any function name. C# gives us the possibility of creating functions without name. But how will this function be called if it has no name. In fact, there is no way to call an anonymous function via code because the name of the function is the handle to call this function.

But we have just seen that the delegates keep handles/references of all the handler functions with them. Delegates don't need the name of the function to invoke them, so the anonymous functions are useful with the delegates only.

What anonymous function does is that instead of having separate code to hook the handler to delegate and body of the handler function, we can simply have the body written in place where we are hooking the function to the delegate. So if I need to achieve the above functionality using anonymous function, I simply need to write it as:

C#
static void Main(string[] args)
{
    // let's say we have a module that notifies the user with low battery
    // here, we are emulating it.
    BatteryLevel batteryLevel = new BatteryLevel();

    // Here, we have another module that is listening to the
    // battery level change, but this time let's implement this using the
    // anonymous function
    batteryLevel.batteryLevelBroadcaster += delegate(int newValue) 
     { Console.WriteLine("(ANOMYMOUS)New battery level is: {0}", newValue);};

    // Now let us simulate the hardware function that will set the battery level
    batteryLevel.CurrentBatteryLevel = 35;
    batteryLevel.CurrentBatteryLevel = 30;
    batteryLevel.CurrentBatteryLevel = 25;
    batteryLevel.CurrentBatteryLevel = 20;
    batteryLevel.CurrentBatteryLevel = 15;
    // Once the above code is run, for each updation, we should get the
    // message written in our delegate function
}

And it will produce the same result as the earlier version but it doesn't need the programmer to write a separate function. This is very useful when the handler function has little code and using this approach gives a cleaner code compared to the earlier version.

Lambda Expressions

Newer version of C# has Lambda expression which has made the anonymous functions more or less obsolete. For the scope of this article, let's understand lambda expression is one more way of creating local anonymous functions that can be used with delegates.

Note: Lambda expression has other merits over anonymous function like it can directly be assigned to expression trees, but we will keep things simple in this article and will not talk about these.

A Lambda expression can be thought of as an alternative to the anonymous methods with the following syntax:

[METHOD PARAMETERS] => [METHOD BODY]

So if we were to write the similar code using lambda expression, we can do that in the following manner:

C#
static void Main(string[] args)
{
    // let's say we have a module that notifies the user with low battery
    // here, we are emulating it.
    BatteryLevel batteryLevel = new BatteryLevel();

    // And finally, there is the third approach where we can use Lambda expression
    // to subscribe to the delegates
    batteryLevel.batteryLevelBroadcaster += 
    (newValue) => Console.WriteLine("(LAMBDA)New battery level is: {0}", newValue);
    // ABOVE LINE WILL WORK ONLY IN VS2008 and above

    // Now let us simulate the hardware function that will set the battery level
    batteryLevel.CurrentBatteryLevel = 35;
    batteryLevel.CurrentBatteryLevel = 30;
    batteryLevel.CurrentBatteryLevel = 25;
    batteryLevel.CurrentBatteryLevel = 20;
    batteryLevel.CurrentBatteryLevel = 15;
    // Once the above code is run, for each updation, we should get the
    // message written in our delegate function
}

Note: In this above code, instead of having the implicit type parameter in lambda expression, we could have specified the type in the expression too.

C#
batteryLevel.batteryLevelBroadcaster += 
    (int newValue) => Console.WriteLine("(LAMBDA)New battery level is: {0}", newValue);

The result of the above code is the same as the earlier versions but the code is much cleaner compared to the earlier versions (one with the handler functions and anonymous methods).

Point of Interest

In this small article, we tried to look into what delegates are and how we can implement custom delegates and their handlers. Delegates have been around from quite some time and this article seems quite late or out of time. I have written this article because someone in the Codeproject Q&A section seems quite confused about the topic. This article has been written from a beginner's perspective. I hope this has been somewhat informative.

History

  • 6th December, 2012: First version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect
India India

I Started my Programming career with C++. Later got a chance to develop Windows Form applications using C#. Currently using C#, ASP.NET & ASP.NET MVC to create Information Systems, e-commerce/e-governance Portals and Data driven websites.

My interests involves Programming, Website development and Learning/Teaching subjects related to Computer Science/Information Systems. IMO, C# is the best programming language and I love working with C# and other Microsoft Technologies.

  • Microsoft Certified Technology Specialist (MCTS): Web Applications Development with Microsoft .NET Framework 4
  • Microsoft Certified Technology Specialist (MCTS): Accessing Data with Microsoft .NET Framework 4
  • Microsoft Certified Technology Specialist (MCTS): Windows Communication Foundation Development with Microsoft .NET Framework 4

If you like my articles, please visit my website for more: www.rahulrajatsingh.com[^]

  • Microsoft MVP 2015

Comments and Discussions

 
GeneralMy vote of 5 Pin
User 1106097916-Nov-14 1:56
User 1106097916-Nov-14 1:56 
QuestionPlease clarify Pin
Member 109797571-Sep-14 19:11
Member 109797571-Sep-14 19:11 
QuestionVote of 5 Pin
shukla_light26-Nov-13 2:29
shukla_light26-Nov-13 2:29 
GeneralMy vote of 5 Pin
DeniskoS11-Sep-13 7:51
DeniskoS11-Sep-13 7:51 
GeneralMy vote of 5 Pin
Mohammed Hameed28-Jun-13 3:17
professionalMohammed Hameed28-Jun-13 3:17 
GeneralMy vote of 5 Pin
Nelly2k26-Mar-13 17:13
Nelly2k26-Mar-13 17:13 
GeneralMy vote of 5 Pin
NemoWang16-Jan-13 15:57
NemoWang16-Jan-13 15:57 
GeneralMy vote of 5 Pin
Renju Vinod15-Jan-13 20:16
professionalRenju Vinod15-Jan-13 20:16 
GeneralMy vote of 5 Pin
Ștefan-Mihai MOGA15-Jan-13 6:48
professionalȘtefan-Mihai MOGA15-Jan-13 6:48 
GeneralNice Pin
Serge Desmedt12-Jan-13 4:55
professionalSerge Desmedt12-Jan-13 4:55 
GeneralMy vote of 5 Pin
Savalia Manoj M9-Jan-13 16:35
Savalia Manoj M9-Jan-13 16:35 
GeneralMy vote of 5 Pin
Unque9-Jan-13 0:19
Unque9-Jan-13 0:19 
GeneralMy vote of 5 Pin
igetorix13-Dec-12 4:04
igetorix13-Dec-12 4:04 
GeneralMy vote of 4 Pin
germ1312-Dec-12 10:44
germ1312-Dec-12 10:44 
Good simple explanation.
GeneralMy vote of 5 Pin
blue_developer11-Dec-12 6:44
blue_developer11-Dec-12 6:44 
GeneralMy vote of 4 Pin
Kevin Bewley10-Dec-12 3:56
Kevin Bewley10-Dec-12 3:56 
GeneralMy vote of 5 Pin
njdnjdnjdnjdnjd8-Dec-12 8:55
njdnjdnjdnjdnjd8-Dec-12 8:55 
GeneralMy vote of 5 Pin
Md. Marufuzzaman7-Dec-12 20:33
professionalMd. Marufuzzaman7-Dec-12 20:33 
GeneralMy vote of 5 Pin
Marc Clifton7-Dec-12 14:59
mvaMarc Clifton7-Dec-12 14:59 
GeneralRe: My vote of 5 Pin
Rahul Rajat Singh10-Dec-12 18:43
professionalRahul Rajat Singh10-Dec-12 18:43 
GeneralMy vote of 5 Pin
GuyThiebaut7-Dec-12 3:06
professionalGuyThiebaut7-Dec-12 3:06 
GeneralMy vote of 5 Pin
wsc09186-Dec-12 17:08
wsc09186-Dec-12 17:08 
GeneralMy vote of 5 Pin
Andy Bantly6-Dec-12 10:25
Andy Bantly6-Dec-12 10:25 
QuestionScore of 5 Pin
CHill606-Dec-12 3:49
mveCHill606-Dec-12 3:49 
Questionmy score of 5 Pin
Danielvrhyn6-Dec-12 2:56
Danielvrhyn6-Dec-12 2:56 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.