C# Delegates, Anonymous Methods, and Lambda Expressions

0

Category :

C# Delegates, Anonymous Methods, and Lambda Expressions.

Delegates

Pointer to a function.
A way to pass methods the same way you pass values and objects around
 
delegate int DiscountDelegate(); 
 
Just like a class, however, it isn't very useful until we create an instance of it.

Remember that a delegate is nothing more then a reference to a method.

Even though DiscountDelegate does not have any constructors, when creating one, there is an implicit constructor that wants a method matching its signature (no params, returning int).

Type in the name in the same way you would call the method; all you do is omit the parentheses.

Another way to think of a delegate is that it defers the execution of a method.

} 

Func

Later, in 3.5, they were nice enough to give us some common delegates to use so we wouldn't have to constantly define our own. They expanded Action and added Func, and the only difference between them is that Func matches methods that return a value and Action matches ones that do not.

This means that we do not need to declare our DiscountDelegate and instead can use Func in its place.

Our delegate's signature now becomes Func. Notice the Calculate method now takes a boolean parameter and that we call discount() using a boolean.

class Program 
{ 
    static void Main(string[] args) 
    { 
        new ShoppingCart().Process(new Func(Calculator.Calculate)); 
    } 
} 
 
class Calculator 
{ 
    public static int Calculate(bool special) 
    { 
        int discount = 0; 
        if (DateTime.Now.Hour < 12) 
        { 
            discount = 5; 
        } 
        else if (DateTime.Now.Hour < 20) 
        { 
            discount = 10; 
        } 
        else if (special) 
        { 
            discount = 20; 
        } 
        else 
        { 
            discount = 15; 
        } 
        return discount; 
    } 
} 
 
class ShoppingCart 
{ 
    public void Process(Func discount) 
    { 
        int magicDiscount = discount(false); 
        int magicDiscount2 = discount(true); 
    } 
}
Type inference allows us to completely omit the explicit creation of Func as long as the method we pass has the proper signature of the expected delegate.
eliminating the need to even explicitly create a Func delegate

// works because Process expects a method that takes a bool and returns int 
new ShoppingCart().Process(Calculator.Calculate); 

Anonymous methods

Anonymous methods let you declare a method body without giving it a name.
Anonymous methods can only be created when using delegates and, in fact, they are created using the delegate keyword.

new ShoppingCart().Process( 
        new Func(delegate(bool x) { return x ? 10 : 5; } 
    )); 

You can put as much or as little logic between the curly braces as you would in any other method.

there is even more trimming we can do. Naturally, we can omit the need to explicitly declare the Func delegate; .NET takes care of that for us when we use the delegate keyword.

new ShoppingCart().Process( 
      delegate(bool x) { return x ? 10 : 5; } 
    );  

The true power of anonymous methods can be seen when using .NET methods that expect delegates as parameters and when responding to events. Previously, you had to create a method for every possible action you wanted to take. Now you can just create them inline and avoid polluting your namespace.

// creates an anonymous comparer 
custs.Sort(delegate(Customer c1, Customer c2) 
{ 
    return Comparer.Default.Compare(c1.ID, c2.ID); 
}); 
 
// creates an anonymous event handler 
button1.Click += delegate(object o, EventArgs e) 
                      { MessageBox.Show("Click!"); }; 

Lambda expressions

From MSDN: 'A lambda expression is an anonymous function that can contain expressions and statements, and can be used to create delegates or expression tree types.'

lambda expressions replace anonymous methods and add many features.

Looking back at our last example, we had trimmed the code down to where we were basically creating the entire discount algorithm in a single line.
new ShoppingCart().Process( 
        new Func(delegate(bool x) { return x ? 10 : 5; } 
    )); 

Lambda expressions use the 'goes to' operator => to indicate what parameters are being passed to the expression.
The compiler takes this a step further, and allows us to omit the types and infers them for us.
If you have two or more parameters, you need to use parentheses: (x,y) =>. If you only have one, however, you don’t need them: x =>.
static void Main(string[] args) 
{ 
    Func del = x => x ? 10 : 5; 
    new ShoppingCart().Process(del); 
} 
// even shorter... 
static void Main(string[] args) 
{ 
    new ShoppingCart().Process(x => x ? 10 : 5); 
} 

Yep, that's it. The boolean type of x is inferred and so is the return type, because Process takes a Func. If we want to implement the full code block like we had before, all we need to do is add the braces.

static void Main(string[] args) 
{ 
    new ShoppingCart().Process( 
    x => { 
        int discount = 0; 
        if (DateTime.Now.Hour < 12) 
        { 
            discount = 5; 
        } 
        else if (DateTime.Now.Hour < 20) 
        { 
            discount = 10; 
        } 
        else if(x) 
        { 
            discount = 20; 
        } 
        else 
        { 
             discount = 15; 
        } 
        return discount; 
    }); 
} 

One last thing…

There is an important difference between using braces and not using them. When you use them, you are creating a 'statement lambda', otherwise it is 'expression lambda'. Statement lambdas can execute multiple statements (hence the need for braces) and can not create expression trees. You will probably only run into this problem when working with the IQueryable interface. The example below shows the problem.

Statement Lambda use curly braces and can execute multiple statements (hence the need for braces) and can not create expression trees.
List list = new List(); 
IQueryable query = list.AsQueryable(); 
list.Add("one"); 
list.Add("two"); 
list.Add("three"); 
 
string foo = list.First(x => x.EndsWith("o")); 
string bar = query.First(x => x.EndsWith("o")); 
// foo and bar are now both 'two' as expected 
foo = list.First(x => { return x.EndsWith("e"); }); //no error 
bar = query.First(x => { return x.EndsWith("e"); }); //error 
bar = query.First((Func)(x => { return x.EndsWith("e"); })); //no error 
The second assignment of bar fails at compile time. This is because IQueryable.First expects an expression as a parameter whereas the extension method List.First expects a delegate. You can force the lambda to evaluate to a delegate (and use the First's method overload) by making a cast as I did in the third assignment to bar.

It's hard to end the discussion here, but I feel I must. Lambdas are basically broken into two categories; the kind that create anonymous methods and delegates, and the kind that create expressions. Expressions are an article by themselves and are not necessarily required knowledge to be a .NET developer (although their implementation in LINQ certainly is).

Informative graphic showing different parts of LINQ query




my thanks to:
http://www.codeproject.com/Articles/47887/C-Delegates-Anonymous-Methods-and-Lambda-Expressio
http://www.codeproject.com/Articles/19154/Understanding-LINQ-C