Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Tip
Začínáte s vývojem softwaru? Začněte nejprve kurzy Začínáme . Než budete používat výrazy lambda, rozvíjejte základní dovednosti v oblasti typů a metod.
Někdy chcete předat malou část chování, funkci, přímo do jiné metody. Můžete například chtít filtrovat seznam, ale podmínka filtrování se změní v závislosti na situaci. Místo psaní samostatné pojmenované metody pro každou možnou podmínku předáte samotnou podmínku jako argument.
Výrazy lambda jsou funkce jazyka C#, která to umožňuje. Výraz lambda je kompaktní vložená funkce, kterou napíšete, aniž byste jí dali název. Pomocí operátoru => šipky oddělíte seznam parametrů od textu:
x => x * 2
Čtení zleva doprava: x je vstupní parametr, => znamená 'jde do,' a x * 2 je tělo. Vypočítá vrácenou hodnotu. Pokud neexistují žádné parametry nebo více než jeden, zabalte je do závorek: () => 42 nebo (left, right) => left + right.
Delegáti podporují výrazy lambda
Aby bylo možné použít výraz lambda, kompilátor jazyka C# musí znát dvě věci: typy parametrů a návratový typ. Tento popis, typy parametrů plus návratový typ, se nazývá typ delegáta.
Typ delegáta je typ, který představuje podpis metody. Proměnná typu delegáta může obsahovat jakoukoli odpovídající metodu, jako je výraz lambda nebo pojmenovaná metoda, pokud se jeho typy parametrů a návratový typ shodují.
Deklarujete typ delegáta pomocí klíčového delegate slova:
delegate int Transform(int value);
Tato deklarace říká: "Transform je typ delegáta pro metody, které přijímají jednu int a vracejí ." int Potom můžete k proměnné tohoto typu přiřadit výraz lambda nebo pojmenovanou metodu:
Transform doubler = x => x * 2; // assign a lambda expression
Transform squarer = Square; // assign a named method
Console.WriteLine(doubler(5)); // 10
Console.WriteLine(squarer(5)); // 25
static int Square(int value) => value * value;
Obě doubler a squarer mají hodnotu typu Transform. Říkáte jim přesně jako běžné metody. Kompilátor ověří, že cokoli, co přiřadíte, odpovídá deklarovanému podpisu.
Předdefinované typy delegátů: Func a Action
Deklarace vlastního typu delegáta pro každou situaci se může opakovat. .NET poskytuje dvě rodiny obecných typů delegátů, Func a Action, které pokrývají většinu scénářů, takže zřídka potřebujete použít klíčové slovo delegate sami.
Obě rodiny jsou ve verzích s nula až šestnácti parametry vstupního typu, takže se škálují na libovolný počet vstupů. Klíčovým rozdílem mezi těmito dvěma rodinami je:
-
System.Func<T,TResult> (a
Func<T1, T2, TResult>atd.) představuje metodu, která vrací hodnotu. Poslední parametr typu je vždy návratový typ; všechny předchozí typy jsou vstupními typy. -
System.Action<T> (a
Action<T1, T2>atd.) představuje metodu, která nevrací nic (void). Všechny parametry typu jsou vstupní typy. System.Action bez parametrů typu představuje metodu bez vstupů a žádnou návratovou hodnotu.
Popisuje například Func<int, int, int> metodu se dvěma int vstupy a jedním int výsledkem.
Action<string> popisuje metodu s jedním string vstupem a žádnou návratovou hodnotou.
Func<int, int, int> add = (left, right) => left + right;
Action<string> report = message => Console.WriteLine($"Report: {message}");
int total = add(5, 9);
report($"5 + 9 = {total}");
V lambdach používejte popisné názvy parametrů, aby čtenáři pochopili záměr bez kontroly celého textu metody.
Předání výrazu lambda metodě
Když metoda deklaruje Func nebo Action parametr, volající předají výraz lambda, který odpovídá danému typu delegáta. Kompilátor zkontroluje, jestli typy parametrů lambda a návratový typ odpovídají deklarovanému typu delegáta. Pokud se neshodují, kód se nezkompiluje.
int[] numbers = [1, 2, 3, 4, 5, 6];
int[] evenNumbers = Filter(numbers, value => value % 2 == 0).ToArray();
Console.WriteLine(string.Join(", ", evenNumbers));
Metoda Filter deklaruje Func<int, bool> parametr s názvem predicate. Typ Func<int, bool> říká volajícím očekávanou strukturu: jeden int vstup, jeden bool výsledek. Volající, odešle tento argument value => value % 2 == 0. Tento vzor se zobrazí v rámci LINQ a mnoha .NET rozhraní API.
Držte výrazy lambda samostatně nezávislé
Výraz lambda může odkazovat na proměnné z okolního kódu. Zachycení znamená, že lambda obsahuje odkaz na proměnnou deklarovanou mimo vlastní tělo. Kombinace lambda a proměnných, které zachycuje, se nazývá uzavření.
Pokud nepotřebujete nic zachytit, přidejte static modifikátor do lambda. Statická lambda může používat pouze vlastní parametry a hodnoty deklarované uvnitř těla. Nemůže zachytit místní proměnné ani stav instance z uzavírajícího prostředí.
Func<int, bool> isEven = static value => value % 2 == 0;
Console.WriteLine(isEven(14));
Console.WriteLine(isEven(15));
Statické lambdy činí záměr zřejmým a zabraňují nechtěným zachycením.
Použijte parametry pro ignorování, když jsou vstupy nerelevantní
Podpis delegáta někdy obsahuje parametry, které nepotřebujete. Použijte příkaz zahození _, abyste explicitně signalizovali tuto volbu.
Mezi běžné příklady patří obslužné rutiny událostí, kde nepoužíváte sender nebo EventArgs, zpětná volání, kde potřebujete jenom několik vstupů, a přetížení LINQ, které poskytují index, který nepoužíváte.
Action<int, int, string> statusUpdate = (_, _, message) => Console.WriteLine(message);
statusUpdate(200, 42, "Operation completed");
Vynechání zlepšují čitelnost, protože ukazují, které parametry jsou důležité.
Události poskytují volitelná oznámení
Událost je mechanismus, který jeden objekt (vydavatel) používá k upozorňovat ostatní objekty (odběratelé), když se něco stane. Vydavatel nemusí vědět, kdo naslouchá nebo kolik předplatitelů existuje. Předplatitelé se rozhodnou přihlásit.
Události jsou založené na delegátech. Událost je pole delegáta s dodatečnými omezeními vynucenými klíčovým slovem event: vnější kód se může pouze přihlásit k odběru (+=) nebo odhlásit odběr (-=) z události; pouze třída, která deklaruje událost, ji může vyvolat (vzbudit).
Konvence .NET pro typy delegátů událostí je System.EventHandler<TEventArgs>, kde T je typ dat zahrnutých v oznámení. Jeho podpis má vždy dva parametry: sender (objekt, který vyvolal událost) a data události typu T.
MessagePublisher publisher = new();
publisher.MessagePublished += (_, message) => Console.WriteLine($"Received: {message}");
publisher.Publish("Records updated");
Procházení kódu:
-
MessagePublisherdeklarujeevent EventHandler<string>? MessagePublished. Klíčovéeventslovo znamená, že uživatelé se můžou jen přihlásit nebo odhlásit z odběru – nemůžou ho vyvolat přímo. -
publisher.MessagePublished += (_, message) => ...přihlásí se k odběru lambda výrazu._zahodí parametrsender, protože ho obslužná rutina nepotřebuje. -
publisher.Publish("Records updated")vyvolá událost a spustí každou předplacenou obslužnou rutinu.
Přihlášení k odběru je volitelné.
?.Invoke(...) Metoda Publish znamená, že událost vyvolá pouze v případě, že je připojen alespoň jeden odběratel. Vydavatel vyvolá událost bez vědomí nebo starostí o to, zda někdo naslouchá.