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.
Delegát je typ, který bezpečně zapouzdřuje metodu, podobně jako ukazatel funkce v jazyce C a C++. Na rozdíl od ukazatelů funkce jazyka C jsou delegáti objektově orientované, typově bezpečné a zabezpečené. Následující příklad deklaruje delegát s názvem Callback
, který může zapouzdřovat metodu, která přebírá řetězec jako argument a vrací void:
public delegate void Callback(string message);
Delegovaný objekt je obvykle vytvořen zadáním názvu metody, kterou delegát zabalí, nebo výrazem lambda. Delegát může být vyvolán, jakmile je takto instanciován. Vyvolání delegáta spouští metodu, která je připojena k instanci delegáta. Do metody se předají parametry předané volajícímu delegátu. Delegát vrátí vrácenou hodnotu, pokud existuje, z metody. Například:
// Create a method for a delegate.
public static void DelegateMethod(string message)
{
Console.WriteLine(message);
}
// Instantiate the delegate.
Callback handler = DelegateMethod;
// Call the delegate.
handler("Hello World");
Typy delegátů jsou odvozeny od Delegate třídy v .NET. Typy delegátů jsou zapečetěné, nemohou být odvozeny a není možné odvodit vlastní třídy z Delegate. Vzhledem k tomu, že instance delegáta je objekt, lze jej předat jako argument nebo přiřadit k vlastnosti. Metoda může přijmout delegáta jako parametr a později volat delegáta. To se označuje jako asynchronní zpětné volání a je běžnou metodou upozorňování volajícího na dokončení dlouhého procesu. Pokud se delegát používá tímto způsobem, kód, který delegát používá, nepotřebuje žádné znalosti o implementaci použité metody. Funkcionalita je podobná té, kterou poskytují rozhraní zapouzdření.
Dalším běžným použitím zpětných volání je definování vlastní metody porovnání a předání tohoto delegáta do metody řazení. Umožňuje, aby se kód volajícího stal součástí algoritmu řazení. Následující příklad metoda používá Del
typ jako parametr:
public static void MethodWithCallback(int param1, int param2, Callback callback)
{
callback("The number is: " + (param1 + param2).ToString());
}
Potom můžete delegáta vytvořenému v předchozím příkladu předat této metodě:
MethodWithCallback(1, 2, handler);
A do konzoly se zobrazí následující výstup:
The number is: 3
MethodWithCallback
nemusí volat konzolu přímo – nemusí být navržena s ohledem na konzolu. Co MethodWithCallback
dělá, je to, že připraví řetězec a předá ho jiné metodě. Delegovaná metoda může používat libovolný počet parametrů.
Pokud je delegát vytvořen tak, aby zabalil metodu instance, delegát odkazuje jak na instanci, tak na metodu. Delegát nezná typ instance, kromě metody, kterou obaluje. Delegát může odkazovat na jakýkoli typ objektu, pokud existuje metoda tohoto objektu, která odpovídá podpisu delegáta. Pokud je delegát vytvořen tak, aby zabalil statickou metodu, odkazuje pouze na metodu. Vezměte v úvahu následující deklarace:
public class MethodClass
{
public void Method1(string message) { }
public void Method2(string message) { }
}
Společně se statickým DelegateMethod
znázorněným dříve máme tři metody, které můžete zabalit do Del
instance.
Delegát může při vyvolání volat více než jednu metodu, což se označuje jako vícenásobné volání. Pokud chcete přidat dodatečnou metodu do seznamu metod delegáta – vyvolávací seznam – stačí přidat dva delegáty pomocí operátorů '+' nebo '+='. Například:
var obj = new MethodClass();
Callback d1 = obj.Method1;
Callback d2 = obj.Method2;
Callback d3 = DelegateMethod;
//Both types of assignment are valid.
Callback allMethodsDelegate = d1 + d2;
allMethodsDelegate += d3;
Obsahuje allMethodsDelegate
tři metody v seznamu vyvolání –Method1
Method2
a DelegateMethod
. Původní tři delegáti, d1
a d2
d3
, zůstávají beze změny. Při vyvolání allMethodsDelegate
jsou všechny tři metody zavolány postupně. Pokud delegát používá referenční parametry, odkaz se postupně předává každé ze tří metod a všechny změny podle jedné metody jsou viditelné pro další metodu. Pokud některá z metod vyvolá výjimku, která není zachycena v metodě, je tato výjimka předána volajícímu delegáta. V seznamu volání nejsou volána žádné další metody. Pokud má delegát návratovou hodnotu nebo parametry out, vrátí návratovou hodnotu a parametry poslední vyvoláné metody. Chcete-li odebrat metodu ze seznamu volání, použijte operátory odčítání nebo odčítání přiřazení (-
nebo -=
). Například:
//remove Method1
allMethodsDelegate -= d1;
// copy AllMethodsDelegate while removing d2
Callback oneMethodDelegate = (allMethodsDelegate - d2)!;
Vzhledem k tomu, že typy delegátů jsou odvozeny z System.Delegate
, lze volat metody a vlastnosti definované touto třídou na delegáta. Pokud chcete například najít počet metod v seznamu vyvolání delegáta, můžete napsat:
int invocationCount = d1.GetInvocationList().GetLength(0);
Delegáti s více než jednou metodou ve svém seznamu vyvolání jsou odvozeni od MulticastDelegate, což je podtřída System.Delegate
. Předchozí kód funguje v obou případech, protože obě třídy podporují GetInvocationList
.
Delegáti vícesměrového vysílání se používají ve velkém rozsahu při zpracování událostí. Zdrojové objekty událostí odesílají oznámení o událostech příjemcům, které se zaregistrovaly k přijetí této události. Pokud chcete zaregistrovat událost, příjemce vytvoří metodu navrženou pro zpracování události, pak vytvoří delegáta pro tuto metodu a předá delegáta zdroji událostí. Zdroj volá delegáta, když dojde k události. Delegát pak zavolá na příjemce metodu pro zpracování události a doručí data události. Zdroj události definuje typ delegáta pro danou událost. Další informace najdete v tématu Události.
Porovnání delegátů dvou různých typů přiřazených v době kompilace způsobí chybu kompilace. Pokud jsou instance delegáta staticky typu System.Delegate
, pak je porovnání povoleno, ale vrátí hodnotu false za běhu. Například:
delegate void Callback1();
delegate void Callback2();
static void method(Callback1 d, Callback2 e, System.Delegate f)
{
// Compile-time error.
Console.WriteLine(d == e);
// OK at compile-time. False if the run-time type of f
// is not the same as that of d.
Console.WriteLine(d == f);
}