Lambda expressions (advanced)

Well, I have used lambda expressions in previous posts already. I was expecting that you know them already.
A Lambda function does not have a name, therefore it is also refered to as anonymous function.
Let’s have a closer look now. In my last post I was introducing delegates and we started with the following example:

// methods
private double Multiply(double a, double b) { return a * b; }
private double Add(double a, double b) { return a + b; }

// a delegate for any of the above methods
private delegate double dCalc(double a, double b);

void Delegates1() {
    dCalc calc = Add; // creates a new delegate
    Console.WriteLine("Sum " + calc(6.0, 3.0));

    calc = Multiply; // creates a new delegate
    Console.WriteLine("Product " + calc(6.0, 3.0));

    Console.ReadLine();
} //

Above code can be shortened by using lambda expressions. It also becomes more legible then:

private delegate double dCalc(double a, double b);

void Lambda1() {
    dCalc calc = (x, y) => x + y;
    Console.WriteLine("Sum " + calc(6.0, 3.0));

    calc = (x, y) => x * y;
    Console.WriteLine("Product " + calc(6.0, 3.0));

    Console.ReadLine();
} //

(x, y) => x + y; is a lambda expression with x and y defined as doubles. The types were defined in the delegate dCalc, which has two doubles as input parameters and one double as return value. The “@” sign is pronounced “at”, likewise the “=>” sign is pronounced “go to” or “goes to”.
As usual you can use curly braces to group multiple statements:
(x, y) => { Console.WriteLine(“hello”); return x + y;}

You don’t have to use parentheses if you only have one parameter.
(x) => x + x;
equals
x => x + x;

And you don’t need the “return” when there is only one statement.
x => x + x;
equals
x => { return x + x; }

C# offers built-in types. They are Func and Action. You can use them to define delegates. Both can take between 0 and 16 parameters. Action has no return value, Func must define a return type in the last parameter.

void Lambda2() {
    // syntax  Func<first parameter type, second parameter type, return value type>
    Func<double, double, int> func = (x, y) => (int)(x + y);

    // syntax Action<first parameter type, second parameter type>
    Action<double, double> action = (x, y) => Console.WriteLine(x + y);
} //

Btw. you need empty parentheses whenever you don’t use any parameters.

Func<int> f = () => 2;

You can be more formal and declare types explicitly.

void Lambda3() {
    Func<double, double, int> func = (double x, double y) => (int)(x + y);
    Action<double, double> action = (double x, double y) => Console.WriteLine(x + y);
} //

If a delegate refers to a local variable it can happen that the local variable does not exist anymore at the time of the lambda expression/(code) execution. It is important to understand that C# is taking care of this problem. The lifetimes of local variables are extended to at least the lifetime of the longest-living delegate. This is called closure.

void Lambda4() {
    string s = "hello world";

    Action action = () => { Thread.Sleep(2000); Console.WriteLine(s); };
    Task.Factory.StartNew(action);

    // Exit the method before the task has completed.
    // This does not invalidate the string s !!!
} //

About Bastian M.K. Ohta

Happiness only real when shared.

Posted on December 17, 2013, in Advanced, Basic, C#, Delegates and tagged , , , , , , , . Bookmark the permalink. 2 Comments.

Leave a comment