C# kennt zwei Begriffe, delegate
und event
. Fangen wir mit dem ersten an.
Delegate
Ein delegate
ist ein Verweis auf eine Methode. Genau wie du einen Verweis auf eine Instanz erstellen kannst:
MyClass instanz = myFactory.GetInstance();
Kannst du einen delegate verwenden, um einen Verweis auf eine Methode zu erstellen:
Action meineMethode = myFactory.GetInstance;
Jetzt, da du diesen Verweis auf eine Methode hast, kannst du die Methode über den Verweis aufrufen:
MyClass instanz = meineMethode();
Aber warum würdest du das tun? Du kannst auch einfach myFactory.GetInstance()
direkt aufrufen. In diesem Fall kannst du. Es gibt jedoch viele Fälle, in denen du nicht möchtest, dass der Rest der Anwendung Kenntnis von myFactory
hat oder myFactory.GetInstance()
direkt aufruft.
Ein offensichtlicher Fall ist, wenn du in der Lage sein möchtest, myFactory.GetInstance()
an einer zentralen Stelle durch myOfflineFakeFactory.GetInstance()
zu ersetzen (auch bekannt als Factory-Methodenmuster).
Factory-Methodenmuster
Wenn du also eine Klasse TheOtherClass
hast und sie myFactory.GetInstance()
verwenden soll, dann sieht der Code ohne Delegates wie folgt aus (du musst TheOtherClass
über den Typ deiner myFactory
informieren):
TheOtherClass toc;
//...
toc.SetFactory(myFactory);
class TheOtherClass
{
public void SetFactory(MyFactory factory)
{
// hier setzen
}
}
Wenn du Delegates verwenden würdest, musst du den Typ meiner Factory nicht offenlegen:
TheOtherClass toc;
//...
Action factoryMethode = myFactory.GetInstance;
toc.SetFactoryMethod(factoryMethode);
class TheOtherClass
{
public void SetFactoryMethod(Action factoryMethode)
{
// hier setzen
}
}
Daher kannst du einer anderen Klasse einen Delegate geben, ohne deinen Typen für sie freizulegen. Das einzige, was du freilegst, ist die Signatur deiner Methode (wie viele Parameter du hast und so weiter).
"Signatur meiner Methode", wo habe ich das schon gehört? Ach ja, Interfaces!!! Interfaces beschreiben die Signatur einer ganzen Klasse. Denke an Delegates als Beschreibung der Signatur nur einer Methode!
Ein weiterer großer Unterschied zwischen einem Interface und einem Delegate besteht darin, dass du beim Schreiben deiner Klasse nicht zu C# sagen musst "diese Methode implementiert diesen Typ eines Delegates". Bei Interfaces musst du sagen "diese Klasse implementiert diesen Typ eines Interfaces".
Weiterhin kann ein Delegate-Verweis (mit einigen Einschränkungen, siehe unten) auf mehrere Methoden verweisen (genannt MulticastDelegate
). Das bedeutet, dass beim Aufrufen des Delegates mehrere explizit angehängte Methoden ausgeführt werden. Ein Objektverweis kann immer nur auf ein Objekt verweisen.
Die Einschränkungen für ein MulticastDelegate
sind, dass die (Methoden/Delegate-)Signatur keinen Rückgabewert haben sollte (void
) und die Schlüsselwörter out
und ref
nicht in der Signatur verwendet werden. Offensichtlich kannst du nicht zwei Methoden aufrufen, die eine Zahl zurückgeben und erwarten, dass sie die gleiche Zahl zurückgeben. Sobald die Signatur übereinstimmt, ist der Delegate automatisch ein MulticastDelegate
.
Event
Events sind nur Eigenschaften (wie die get;set;-Eigenschaften für Instanzfelder), die eine Abonnement auf den Delegate von anderen Objekten freigeben. Diese Eigenschaften unterstützen jedoch kein get;set;. Stattdessen unterstützen sie add; remove;
Du kannst also haben:
Action meinFeld;
public event Action MeineEigenschaft
{
add { meinFeld += value; }
remove { meinFeld -= value; }
}
Verwendung in UI (WinForms, WPF, UWP usw.)
Also wissen wir jetzt, dass ein Delegate ein Verweis auf eine Methode ist und dass wir ein Event haben können, um der Welt mitzuteilen, dass sie uns ihre Methoden geben können, die von unserem Delegate referenziert werden können. Wenn wir also ein UI-Button sind, können wir alle, die daran interessiert sind, ob ich geklickt wurde, bitten, ihre Methode bei uns zu registrieren (über das von uns freigegebene Event). Wir können alle diese Methoden verwenden, die uns gegeben wurden, und sie durch unseren Delegate referenzieren. Und dann warten wir und warten... bis ein Benutzer kommt und auf diesen Button klickt, dann haben wir genug Grund, den Delegate aufzurufen. Und weil der Delegate auf all diese uns gegebenen Methoden verweist, werden all diese Methoden aufgerufen. Wir wissen nicht, was diese Methoden tun, noch wissen wir, welche Klasse diese Methoden implementiert. Alles, worüber wir uns sorgen, ist, dass sich jemand für unser Klicken interessiert und uns einen Verweis auf eine Methode gegeben hat, die unserer gewünschten Signatur entspricht.
Java
Sprachen wie Java haben keine Delegates. Sie verwenden stattdessen Interfaces. Der Weg, wie sie das machen, besteht darin, alle, die an 'uns angeklickt werden' interessiert sind, aufzufordern, eine bestimmte Schnittstelle zu implementieren (mit einer bestimmten Methode, die wir aufrufen können), dann geben sie uns die ganze Instanz, die die Schnittstelle implementiert. Wir halten eine Liste aller Objekte, die diese Schnittstelle implementieren, und können ihre 'bestimmte Methode, die wir aufrufen können' aufrufen, wann immer wir angeklickt werden.