C# Delegates, Anonymous Methods, Lambda, Generic Delegates, Expression Trees Code Examples

C# Delegates, Anonymous Methods, Lambda, Generic Delegates, Expression Trees Code Examples

Some textbooks and blogs mention events when talking about delegates. Although events are an instance of delegates, to make it easier to understand, today we only talk about delegates, not events.

Last updated 9/18/2021 11:39 AM
QueryWord
5 min read
Category
.NET
Tags
.NET C# Expression Trees Generic Delegates Anonymous Methods

Minute 1: Delegates

Some textbooks and blog posts mention events when talking about delegates. Although events are instances of delegates, for easier understanding, today we'll only discuss delegates, not events. Let's start with some code:

The code below demonstrates a delegate application. A delegate consists of three steps:

class Program
{
    //step01: First, define a delegate using the delegate keyword.
    public delegate int CalculatorAdd(int x, int y);

    static void Main(string[] args)
    {
        //step03: Use this method to instantiate the delegate.
        CalculatorAdd cAdd = new CalculatorAdd(Add);

        //int result = cAdd(5, 6);
        int result = cAdd.Invoke(5, 6);
    }

    // step02: Declare a method that matches the delegate.
    public static int Add(int x, int y)
    {
        return x + y;
    }
}
  • step01: First, define a delegate using the delegate keyword.
  • step02: Declare a method that matches the delegate.
  • step03: Use this method to instantiate the delegate.

At this point, the delegate application is complete and you can invoke the delegate.

Minute 2: Anonymous Methods

In the previous minute, we learned that completing a delegate application involves three steps, and not a single one can be skipped. If you try to skip a step, you might end up in trouble. But Microsoft isn't afraid of trouble; they decided to turn three steps into two! So Microsoft used anonymous methods to simplify the three steps above. Anonymous methods are somewhat optional in C#; they are just syntactic sugar that adds some extra flair to C#.

class Program
{
    //step01: First, define a delegate using the delegate keyword.
    public delegate int CalculatorAdd(int x, int y);

    static void Main(string[] args)
    {
        //step02: Use the syntax delegate(int x, int y) { return x + y; } to assign a method to the delegate.
        CalculatorAdd cAdd = delegate (int x, int y) { return x + y; };

        int result = cAdd.Invoke(5, 6);
    }
}
  • step01: First, define a delegate using the delegate keyword.
  • step02: Use the syntax delegate(int x, int y) { return x + y; } to assign a method to the delegate. This syntax is actually an anonymous method.

You'll be surprised to find that we've reduced three steps to two!

Minute 3: Lambda Expressions

An already simple program becomes more profound when you add a few delegate keywords. Profound things are understood by fewer people, so this can be used as leverage for a salary increase. However, Microsoft's design philosophy for C# is simplicity and ease of use. So Microsoft found ways to simplify the anonymous method delegate(int x, int y) { return x + y; }, and Lambda expressions came into being. Let's look at several ways to write a Lambda expression:

class Program
{
    public delegate int CalculatorAdd(int x, int y);
    static void Main(string[] args)
    {
        //Method 1:
        CalculatorAdd cAdd1 = (int x, int y) => { return x + y; };
        int result1 = cAdd1(5, 6);

        //Method 2:
        CalculatorAdd cAdd2 = (x, y) => { return x + y; };
        int result2 = cAdd2(5, 6);

        //Method 3:
        CalculatorAdd cAdd3 = (x, y) => x + y;
        int result3 = cAdd2(5, 6);
    }
}

Minute 4: Generic Delegates

With each new version of .NET, there must be something different from the previous version, otherwise how would Microsoft's engineers report to their boss? So Microsoft introduced new features again.

class Program
{
    static void Main(string[] args)
    {
        //Method 1:
        Func<int, int, int> cAdd1 = (int x, int y) => { return x + y; };
        int result1 = cAdd1(5, 6);

        //Method 2:
        Func<int, int, int> cAdd2 = (x, y) => { return x + y; };
        int result2 = cAdd2(5, 6);

        //Method 3:
        Func<int, int, int> cAdd3 = (x, y) => x + y;
        int result3 = cAdd2(5, 6);
    }
}

Whether using anonymous methods or Lambda expressions, completing a delegate application still requires two steps: one to define a delegate and another to instantiate it with a method. Microsoft decided to combine these two steps into one: using Func to simplify the definition of a delegate.

Thus, a delegate application can now be accomplished with a single statement like Func<int, int, int> cAdd3 = (x, y) => x + y;. The Func here is what is called a generic delegate.

Minute 5: Expression Trees

Expression trees actually have little to do with delegates anymore. If we must relate them, we could say that expression trees are containers for delegates. To be more technical, expression trees are a data structure that stores Lambda expressions. When you need a Lambda expression, you can retrieve it from the expression tree and call Compile() to use it directly, as shown in the code below:

class Program
{
    static void Main(string[] args)
    {
        Expression<Func<int, int, int>> exp = (x, y) => x + y;
        Func<int, int, int> fun = exp.Compile();
        int result = fun(2, 3);
    }
}
Keep Exploring

Related Reading

More Articles