Delegáty a výrazy lambda
Delegát definuje typ, který představuje odkazy na metody, které mají konkrétní seznam parametrů a návratový typ. Metoda (statická nebo instance), jejíž seznam parametrů a návratový typ odpovídají, lze přiřadit k proměnné tohoto typu, poté volat přímo (s příslušnými argumenty) nebo předat jako samotný argument jiné metodě a pak ji volat. Následující příklad ukazuje použití delegáta.
using System;
using System.Linq;
public class Program
{
public delegate string Reverse(string s);
static string ReverseString(string s)
{
return new string(s.Reverse().ToArray());
}
static void Main(string[] args)
{
Reverse rev = ReverseString;
Console.WriteLine(rev("a string"));
}
}
- Řádek
public delegate string Reverse(string s);
vytvoří typ delegáta metody, která přebírá řetězcový parametr a pak vrátí parametr řetězce. - Metoda
static string ReverseString(string s)
, která má úplně stejný seznam parametrů a návratový typ jako definovaný typ delegáta, implementuje delegáta. - Řádek
Reverse rev = ReverseString;
ukazuje, že můžete přiřadit metodu proměnné odpovídajícího typu delegáta. - Řádek
Console.WriteLine(rev("a string"));
ukazuje, jak použít proměnnou typu delegáta k vyvolání delegáta.
Za účelem zjednodušení procesu vývoje obsahuje rozhraní .NET sadu typů delegátů, které mohou programátoři znovu použít a nemusí vytvářet nové typy. Tyto typy jsou Func<>
, Action<>
a Predicate<>
je možné je použít bez nutnosti definovat nové typy delegátů. Existují určité rozdíly mezi těmito třemi typy, které souvisejí se způsobem jejich použití:
Action<>
se používá, když je potřeba provést akci pomocí argumentů delegáta. Metoda, kterou zapouzdřuje, nevrací hodnotu.Func<>
se obvykle používá, když máte k dispozici transformaci, to znamená, že potřebujete transformovat argumenty delegáta na jiný výsledek. Dobrým příkladem jsou projekce. Metoda, kterou zapouzdří, vrátí zadanou hodnotu.Predicate<>
se používá, když potřebujete zjistit, jestli argument splňuje podmínku delegáta. Dá se také zapsat jakoFunc<T, bool>
, což znamená, že metoda vrátí logickou hodnotu.
Teď můžeme vzít výše uvedený příklad a přepsat ho pomocí delegáta Func<>
místo vlastního typu. Program bude dál běžet úplně stejně.
using System;
using System.Linq;
public class Program
{
static string ReverseString(string s)
{
return new string(s.Reverse().ToArray());
}
static void Main(string[] args)
{
Func<string, string> rev = ReverseString;
Console.WriteLine(rev("a string"));
}
}
V tomto jednoduchém příkladu se zdá, že je metoda definovaná mimo metodu Main
trochu nadbytečná. Rozhraní .NET Framework 2.0 zavedlo koncept anonymních delegátů, který umožňuje vytvářet "vložené" delegáty bez nutnosti zadávat další typ nebo metodu.
V následujícím příkladu anonymní delegát vyfiltruje seznam jenom na sudá čísla a pak je vytiskne do konzoly.
using System;
using System.Collections.Generic;
public class Program
{
public static void Main(string[] args)
{
List<int> list = new List<int>();
for (int i = 1; i <= 100; i++)
{
list.Add(i);
}
List<int> result = list.FindAll(
delegate (int no)
{
return (no % 2 == 0);
}
);
foreach (var item in result)
{
Console.WriteLine(item);
}
}
}
Jak vidíte, tělo delegáta je jenom sada výrazů, stejně jako jakýkoli jiný delegát. Ale místo toho, aby to byla samostatná definice, zavedli jsme ji ad hoc do volání List<T>.FindAll metody.
I s tímto přístupem však stále existuje mnoho kódu, který můžeme zahodit. Tady přichází do hry výrazy lambda . Výrazy lambda, zkráceně jen lambda, byly zavedeny v jazyce C# 3.0 jako jeden ze základních stavebních bloků jazyka LINQ (Language Integrated Query). Jsou to jen pohodlnější syntaxe pro použití delegátů. Deklarují seznam parametrů a tělo metody, ale nemají vlastní formální identitu, pokud nejsou přiřazené delegátovi. Na rozdíl od delegátů je možné je přímo přiřadit jako pravou stranu registrace události nebo v různých klauzulích a metodách LINQ.
Vzhledem k tomu, že výraz lambda je jen dalším způsobem určení delegáta, měli bychom být schopni přepsat výše uvedenou ukázku tak, aby místo anonymního delegáta použil výraz lambda.
using System;
using System.Collections.Generic;
public class Program
{
public static void Main(string[] args)
{
List<int> list = new List<int>();
for (int i = 1; i <= 100; i++)
{
list.Add(i);
}
List<int> result = list.FindAll(i => i % 2 == 0);
foreach (var item in result)
{
Console.WriteLine(item);
}
}
}
V předchozím příkladu je i => i % 2 == 0
použitý výraz lambda . Opět je to jen pohodlná syntaxe pro použití delegátů. To, co se děje pod obálkami, se podobá tomu, co se stane s anonymním delegátem.
Lambdy jsou opět pouze delegáty, což znamená, že je můžete bez problémů použít jako obslužnou rutinu události, jak ukazuje následující fragment kódu.
public MainWindow()
{
InitializeComponent();
Loaded += (o, e) =>
{
this.Title = "Loaded";
};
}
Operátor +=
v tomto kontextu se používá k přihlášení k odběru události. Další informace najdete v tématu Jak se přihlásit k odběru a odhlásit odběr událostí.
Další informace a zdroje informací
Váš názor
Odeslat a zobrazit názory pro