Verwenden von Delegaten (C#-Programmierhandbuch)
Ein Delegat ist ein Typ, der ähnlich einem Funktionszeiger in C und C++ eine Methode sicher kapselt.Delegaten sind im Gegensatz zu Funktionszeigern in C jedoch objektorientiert und typsicher und bieten allgemein eine größere Sicherheit.Der Typ eines Delegaten wird durch den Namen des Delegaten definiert.Im folgenden Beispiel wird ein Delegat mit dem Namen Del deklariert, der eine Methode kapseln kann, die eine Zeichenfolge als Argument annimmt und void zurückgibt:
public delegate void Del(string message);
Ein Delegatobjekt wird normalerweise durch Bereitstellen des Namens der Methode, die der Delegat umschließt, oder mit einer anonymen Methode erstellt.Sobald ein Delegat instanziiert ist, wird ein Methodenaufruf, der an den Delegaten erfolgt, von diesem an die Methode weitergegeben.Auch die Parameter, die der Delegat vom Aufrufer erhält, gibt er an die Methode weiter. Ein Rückgabewert wird gegebenenfalls von der Methode wieder über den Delegaten an den Aufrufer weitergegeben.Dies wird als Aufrufen des Delegaten bezeichnet.Ein instanziierter Delegat kann wie die umschlossene Methode selbst aufgerufen werden.Beispiele:
// Create a method for a delegate.
public static void DelegateMethod(string message)
{
System.Console.WriteLine(message);
}
// Instantiate the delegate.
Del handler = DelegateMethod;
// Call the delegate.
handler("Hello World");
Delegattypen werden in .NET Framework von der Delegate-Klasse abgeleitet.Delegattypen sind versiegelt, d. h., von ihnen kann nicht abgeleitet werden, und es ist nicht möglich, benutzerdefinierte Klassen von Delegate abzuleiten.Da der instanziierte Delegat ein Objekt ist, kann er als Parameter übergeben oder einer Eigenschaft zugewiesen werden.Eine Methode kann also einen Delegaten als Parameter erhalten und diesen zu einem späteren Zeitpunkt aufrufen.Dies wird als asynchroner Rückruf bezeichnet und ist eine übliche Methode, einem Aufrufer mitzuteilen, dass ein lange dauernder Prozess beendet wurde.Wenn ein Delegat auf diese Weise verwendet wird, benötigt der Code, der den Delegaten verwendet, keine Informationen zum Typ oder zur Implementierung der verwendeten Methode.Die Funktionalität ist der Kapselung ähnlich, die von Schnittstellen bereitgestellt wird.Weitere Informationen finden Sie unter Wann sind Delegaten Schnittstellen vorzuziehen?.
Eine weitere gebräuchliche Verwendung von Rückrufen ist das Definieren einer benutzerdefinierten Vergleichsmethode und der Übergabe dieses Delegaten an eine Sortiermethode.Dies ermöglicht dem Code des Aufrufers, Teil des Sortieralgorithmus zu werden.In der folgenden Beispielmethode wird der Del-Typ als Parameter verwendet:
public void MethodWithCallback(int param1, int param2, Del callback)
{
callback("The number is: " + (param1 + param2).ToString());
}
Sie können anschließend den oben erstellten Delegaten an diese Methode übergeben:
MethodWithCallback(1, 2, handler);
und empfangen an der Konsole die folgende Ausgabe:
The number is: 3
Für die Verwendung des Delegaten als Abstraktion muss MethodWithCallback die Konsole nicht direkt aufrufen – beim Entwurf muss keine Konsole beachtet werden.MethodWithCallback bereitet einfach eine Zeichenfolge vor und übergibt sie an eine andere Methode.Dies ist besonders leistungsstark, da eine delegierte Methode eine beliebige Anzahl Parameter verwenden kann.
Wenn ein Delegat erstellt wird, um eine Instanzenmethode zu umschließen, verweist der Delegat sowohl auf die Instanz als auch auf die Methode.Ein Delegat weiß nichts über den Instanztyp, abgesehen von der zu umschließenden Methode. Er kann also auf einen beliebigen Objekttyp verweisen, solange das Objekt eine Methode hat, deren Signatur mit der des Delegaten übereinstimmt.Wenn ein Delegat erstellt wird, um eine statische Methode zu umschließen, verweist er nur auf die Methode.Betrachten Sie hierzu folgende Deklarationen:
public class MethodClass
{
public void Method1(string message) { }
public void Method2(string message) { }
}
Zusammen mit der zuvor dargestellten statischen DelegateMethod verfügen Sie nun über drei Methoden, die mit einer Del-Instanz umschlossen werden können.
Ein aufgerufener Delegat kann mehr als eine Methode aufrufen.Das wird als Multicasting bezeichnet.Um zur Methodenliste (der Aufrufliste) eines Delegaten eine weitere Methode hinzuzufügen, müssen lediglich zwei Delegaten mithilfe des Additions- oder des Additionszuweisungsoperators ('+' oder '+=') hinzugefügt werden.Beispiele:
MethodClass obj = new MethodClass();
Del d1 = obj.Method1;
Del d2 = obj.Method2;
Del d3 = DelegateMethod;
//Both types of assignment are valid.
Del allMethodsDelegate = d1 + d2;
allMethodsDelegate += d3;
Nun enthält die Aufrufliste von allMethodsDelegate drei Methoden: Method1, Method2 und DelegateMethod.Die ursprünglichen drei Delegaten (d1, d2 und d3) bleiben unverändert.Wenn allMethodsDelegate aufgerufen wird, werden alle drei Methoden der Reihe nach aufgerufen.Falls der Delegat Verweisparameter verwendet, wird der Verweis der Reihe nach an die Methoden weitergereicht, und Änderungen einer Methode sind für die folgende Methode sichtbar.Löst eine der Methoden eine Ausnahme aus, die nicht innerhalb der Methode abgefangen werden kann, wird die Ausnahme an den Aufrufer des Delegaten weitergegeben, und es wird keine weitere Methode aus der Aufrufliste aufgerufen.Falls der Delegat über einen Rückgabewert und/oder out-Parameter verfügt, gibt er den Rückgabewert und die Parameter der letzten aufgerufenen Methode zurück.Mit dem Subtraktions- oder dem Subtraktionszuweisungsoperator ('-' oder '-=') kann eine Methode aus der Aufrufliste entfernt werden.Beispiele:
//remove Method1
allMethodsDelegate -= d1;
// copy AllMethodsDelegate while removing d2
Del oneMethodDelegate = allMethodsDelegate - d2;
Da Delegattypen von System.Delegate abgeleitet werden, können die von dieser Klasse definierten Methoden und Eigenschaften vom Delegaten aufgerufen werden.Um zum Beispiel die Anzahl der Methoden in der Aufrufliste eines Delegaten zu ermitteln, verwenden Sie folgenden Code:
int invocationCount = d1.GetInvocationList().GetLength(0);
Delegaten mit mehr als einer Methode in der Aufrufliste sind von MulticastDelegate, einer Unterklasse von System.Delegate, abgeleitet.Der obige Code funktioniert in jedem Fall, da beide Klassen GetInvocationList unterstützen.
Multicastdelegaten werden ausgiebig bei der Ereignisbehandlung verwendet.Ereignisquellenobjekte senden Ereignisbenachrichtigungen an Empfängerobjekte, die sich registriert haben, um dieses Ereignis zu empfangen.Um sich für ein Ereignis zu registrieren, erstellt der Empfänger zuerst eine Methode zur Behandlung des Ereignisses, dann einen Delegaten für die Methode und übergibt den Delegaten an die Ereignisquelle.Die Quelle ruft den Delegaten auf, wenn das Ereignis eintritt.Der Delegat ruft dann die Ereignisbehandlungsmethode des Empfängers auf und liefert die Ereignisdaten.Der Delegattyp für ein Ereignis wird von der Ereignisquelle definiert.Weitere Informationen finden Sie unter Ereignisse (C#-Programmierhandbuch).
Der Vergleich von zwei Delegaten verschiedenen Typs, die zur Kompilierzeit zugewiesen wurden, führt zu einem Kompilierungsfehler.Falls die Delegatinstanzen statisch vom Typ System.Delegate sind, ist der Vergleich zulässig, ergibt aber zur Laufzeit false.Beispiele:
delegate void Delegate1();
delegate void Delegate2();
static void method(Delegate1 d, Delegate2 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.
System.Console.WriteLine(d == f);
}
Siehe auch
Referenz
Delegaten (C#-Programmierhandbuch)
Verwenden von Varianz in Delegaten (C# und Visual Basic)
Verwenden von Varianz für die generischen Delegaten Func und Action (C# und Visual Basic)
Ereignisse (C#-Programmierhandbuch)