Wyrażenia Lambda, czyli delegaty cz.2

Wyrażenia Lambda

Wyrażenia lambda to anonimowa funkcja, której używamy do stworzenia delegatów i drzew wyrażeń (ang. expression Trees). Z podstawami delegatów możecie się zapoznać w moim wcześniejszym poście. Wyrażenia lambda pojawiły się pierwszy raz w C# 3.0. Jedną z podstawowych zalet wyrażeń lambda jest zapewnienie bardziej zwartej składni niż tej występującej w metodach anonimowych. Za pomocą ich pomocą możesz napisać funkcje lokalne, które mogą być przekazywane jako argumenty lub zwracane jako wartość wywołań funkcji. Są one bardzo często wykorzystywane do pisania zapytań LINQ.

 

Składnia

Wyrażenie lambda można napisać na wiele sposobów. Konieczny jest operator lambda => , po jego lewej stronie powinniśmy parametry wejściowe ( o ile są konieczne ). Po prawej stronie operatora znajduje się blok wyrażeń.

Ogólnie składnia wygląda tak:

 (parametry) => { zwracana wartość }

Tak samo działające wyrażenie można zapisać na wiele sposobów:

 x => x * x;
(x) => x * x;
(int x) => x * x;
x => { return x * x; };
(x) => { return x * x; };
(int x) => { return x * x; };

ad 1. Zapis pierwszy jest podstawową formą zapisu. Wychodząc od niej omówimy kolejne zmiany.

ad 2. W tym przypadku nawiasy są opcjonalne ponieważ używamy tylko jednego parametru. Jednak w przypadku ich większej ilości nawias jest wymagany.

ad 3. Możemy chcieć jawnie podać typ parametru, wtedy również musi on się znaleźć w nawiasach nawet jeżeli jest tylko jeden.

ad 4. Jeżeli mamy taką potrzebę lub chęć to zamiast pojedynczego wyrażenia możemy użyć instrukcję blokową. Jeżeli w tym przypadku wyrażenie ma zwracać jakąś wartość, trzeba użyć instrukcji return. Zazwyczaj stosuje się tą formę, jeżeli istnieje potrzeba wykonania więcej operacji wewnątrz.

ad 5 i 6. Jest to połączenie wcześniej opisanych możliwości zapisu.

Istnieje również możliwość napisana wyrażenia lambda, które nie przyjmuje żadnego parametru:

 () => SomeMethod() 

Poniżej kilka przykładów:

using System;

namespace LambdaExpressions
{
    class Program
    {
        delegate int Delegate1(int i);
        delegate void Delegate2(string s);
        delegate bool Delegate3(int x, string s);
        static void Main(string[] args)
        {
            Delegate1 delegete1 = x => x * x;

            Delegate2 delegete2 = n => { string s = n + " World"; 
                          Console.WriteLine(s); };

            Delegate3 delegete3 = (int x, string s) => s.Length > x;

            int firstDelegateValue = delegete1(5); // 25
            delegete2("Hello"); // Hello World
            bool thirdDelegateValue = delegete3(5, "SomeWord"); // True                        
        }
    }
}

Tworzenie delegatu jako func

Delegat można utworzyć jako Func<int, bool> myFunc, gdzie int jest parametrem wejściowym, a bool jest wartością zwracaną. Wartość zwracana jest zawsze określona w ostatnim parametrze typu. Func<int, string, bool> definiuje delegata z dwoma parametrami wejściowymi, int i string oraz typem zwrotu bool. Następujący delegat Func podczas wywoływania zwraca true lub false w celu wskazania, czy parametr wejściowy jest równy 5:

 Func<int, bool> myFunc = x => x == 5;  
 bool result = myFunc(4); // zwróci false

Poniżej jeszcze parę przykładów jak na różne sposoby można podejść do funka z dwoma parametrami:

using System;

namespace LambdaExpressions
{
    class Program
    {
        static void Main(string[] args)
        {
            // Func z jednym parametrem
            Func<int, bool> myFunc = x => x == 5;  
            bool result = myFunc(4); // zwróci false


            // Func z dwoma parametrami i różnym podejściami do rozwiązania
            Func<int, string, bool> myFunk2 = CompareStringLengthToInt;
            bool result2 = myFunk2(4, "someString"); // zwróci false

            Func<int, string, bool> myFunk3 = delegate(int i, string s)
            {
                return s.Length == i;
            };
            bool result3 = myFunk3(10, "someString"); // zwróci true   

            Func<int, string, bool> myFunk4 = (int i, string s) => s.Length == i;
            bool result4 = myFunk4(15, "someString"); // zwróci false          
        }

        private static bool CompareStringLengthToInt(int i, string s)
            => s.Length == i;
    }
}

Współpraca z LINQ

Wyrażenia lambda świetnie nadają się do współpracy z LINQ. Linq to technologia służąca do odpytywania obiektów o składni podobnej do SQL’a. Tym tematem dokładniej zajmę się w innym poście poświęconym głównie LINQ. Poniżej przedstawiam prosty przykład użycia wyrażeń lambda w kooperacji z LINQ:

using System;
using System.Linq;

namespace LambdaExpressions
{
    class Program
    {
        static void Main(string[] args)
        {
            int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 }; 

            int oddNumbers = numbers.Count(n => n % 2 == 1);  

            var firstNumbersLessThan6 = numbers.TakeWhile(n => n < 6); var firstSmallNumbers = numbers.TakeWhile((n, index) => n >= index);
        }
    }
}

Wyniki prezentują się następująco

2 myśli na temat “Wyrażenia Lambda, czyli delegaty cz.2

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *