Programowanie w języku C#

Wyrażenie Lambda


Wstęp


Przed podejściem do wyrażeń lambda warto zapoznać się z Delegacje.

Definicja


Wyrażenia lambda to funkcje anonimowe, które zostały wprowadzone do C# w wersji 3.0. Nie należy jednak mylić ich z metodami anonimowymi z wersji 2.0.
Metody anonimowe: https://msdn.microsoft.com/pl-pl/library/0yw3tz5k.aspx

Składnia


Wyrażenie lambda ma następującą składnię:
(parametry) => {zwracana wartość}
 
(int a, int b) => {return a + b;}


Prosty przykład:
Func<int, int, int> foo = (int a, int b) => { return a + b; };
 
Console.WriteLine(foo(5, 4));


Jednak składnia wyrażenia nie zawsze musi tak wyglądać, mianowicie:

  • Typ parametru nie musi być podawany

  • Jeśli podawany jest jeden parametr to nawiasy () nie muszą występować

  • Jeśli jedyną instrukcją jest return to możemy pominąć nawiasy {}, słówko return oraz średnik

Dzięki temu możemy uzyskać jeszcze krótsze formy np.:
Func<int, int, int> foo = (a, b) => { return a + b; };
Func<int, int, int> foo = (int a, int b) =>  a + b;
Func<int, int, int> foo = (a, b) =>  a + b;
Func<int, int> foo = a => a * 5;


Co jeśli nie chcemy przesyłać parametrów, albo chcemy wykonać więcej niż jedną instrukcję? Żaden problem:
Func<int> foo = () =>
{
    int a = 5;
    return a;
};
 
Console.WriteLine(foo());


Zmienne zewnętrzne


W wyrażeniach lambda możliwe jest odnoszenie się do zmiennych, do których mamy dostęp w danym zakresie:
int x = 5;
 
Func<int> foo = () => x;
 
Console.WriteLine(foo());


Ponadto nawet jeśli zmodyfikujemy wartość x między linijką 2 i 4 to w wyrażeniu i tak będzie aktualna wartość:
int x = 5;
 
Func<int> foo = () => x;
 
x = 6;
 
Console.WriteLine(foo());


Możemy nie mieć nawet dostępu do zmiennej x w momencie wywołania foo np. wtedy gdy zwrócimy wyrażenie jako wynik metody, wtedy x będzie posiadało ostatnią aktualną wartość:
using System;
 
class Program
{
    static void Main()
    {
        TestFoo.Foo();
 
        Console.ReadKey();
    }
}
 
class TestFoo
{
    public static Func<int> Testuj()
    {
        int x = 5;
 
        Func<int> foo = () => x;
 
        x = 6;
 
        return foo;
    }
 
    public static void Foo()
    {
        var foo = Testuj();
 
        Console.WriteLine(foo());
    }
}


Inny dosyć ciekawy przykład, który pozwala nam zobaczyć możliwości zewnętrznych zmiennych:
using System;
 
class Program
{
    static void Main()
    {
        TestFoo.WiekszeNizN(100);
 
        Console.ReadKey();
    }
}
 
class TestFoo
{
    public static Func<int, bool> TestujacaFunkcja(int n)
    {
        return x => x > n;
    }
 
    public static void WiekszeNizN(int x)
    {
        var funkcja = TestujacaFunkcja(50);
 
        Console.WriteLine(funkcja(x));
    }
}


Praktyczny przykład


Wyrażenia lambda wykorzystywane są między innymi w LINQ, poniżej przykład, który przeszukuje listę i zwraca nową listę tylko tych zmiennych, które spełniają warunek:
using System;
using System.Linq;
using System.Collections.Generic;
 
 
class Program
{
    static void Main()
    {
        var lista = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
 
        var nowaLista = lista.Where(zmienna => zmienna > 5).ToList<int>();
 
        foreach (var liczba in nowaLista)
        {
            Console.WriteLine(liczba);
        }
 
        Console.ReadKey();
    }
}


W powyższym kodzie, przekazujemy wyrażenie lambda do metody Where. Metoda Where dla każdego elementu w liście będzie wywoływała przesłane wyrażenie podając dany element jako parametr wejściowy, a na podstawie rezultatu(true/false) dodawała lub nie element do nowej kolekcji(zwracanej przez metodę Where).