Freigeben über


Verwenden von Stellvertretungen (C#-Programmierhandbuch)

Ein Delegat ist ein Typ, der eine Methode sicher kapselt, ähnlich wie ein Funktionszeiger in C und C++. Im Gegensatz zu C-Funktionszeigern sind Delegates objektorientiert, typsicher und sicher. Im folgenden Beispiel wird ein Delegat mit dem Namen Callback deklariert, der eine Methode kapselt, die eine Zeichenfolge als Argument verwendet und "void" zurückgibt:

public delegate void Callback(string message);

Ein Delegatobjekt wird normalerweise durch Angabe des Namens der Methode, die der Delegat umschließt, oder mit einem Lambdaausdruck erstellt. Ein Delegat kann auf diese Weise aufgerufen werden, sobald er instanziiert wurde. Durch Aufrufen eines Delegaten wird die Methode aufgerufen, die der Delegateninstanz zugeordnet ist. Die Parameter, die vom Aufrufer an den Delegaten übergeben werden, werden an die Methode übergeben. Der Delegat gibt den Rückgabewert (sofern vorhanden) aus der Methode zurück. Beispiel:

// 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");

Delegattypen werden von der Delegate Klasse in .NET abgeleitet. Stellvertretungstypen sind versiegelt, können nicht abgeleitet werden, und es ist nicht möglich, benutzerdefinierte Klassen abzuleiten.Delegate Da der instanzierte Delegat ein Objekt ist, kann er als Argument übergeben oder einer Eigenschaft zugewiesen werden. Eine Methode kann einen Delegaten als Parameter akzeptieren und den Delegaten zu einem späteren Zeitpunkt aufrufen. Dies wird als asynchroner Rückruf bezeichnet und ist eine gängige Methode zum Benachrichtigen eines Aufrufers, wenn ein langer Prozess abgeschlossen ist. Wenn ein Delegat auf diese Weise verwendet wird, benötigt der Code, der den Delegaten verwendet, keine Kenntnisse über die Implementierung der verwendeten Methode. Die Funktion ähnelt den bereitgestellten Kapselungsschnittstellen.

Ein weiterer häufiger Einsatzbereich von Rückrufen ist die Definition einer benutzerdefinierten Vergleichsmethode und die Übergabe dieses Delegaten an eine Sortiermethode. Er ermöglicht es dem Aufrufercode, Teil des Sortieralgorithmus zu werden. Die folgende Beispielmethode verwendet den Del Typ als Parameter:

public static void MethodWithCallback(int param1, int param2, Callback callback)
{
    callback("The number is: " + (param1 + param2).ToString());
}

Anschließend können Sie die im vorherigen Beispiel erstellte Stellvertretung an diese Methode übergeben:

MethodWithCallback(1, 2, handler);

Und enthält die folgende Ausgabe, die auf der Konsole angezeigt wird:

The number is: 3

MethodWithCallback muss die Konsole nicht direkt aufrufen – es muss nicht mit einer Konsole im Sinn entworfen werden. Was MethodWithCallback tut, ist, eine Zeichenfolge vorzubereiten und die Zeichenfolge an eine andere Methode zu übergeben. Eine delegierte Methode kann eine beliebige Anzahl von Parametern verwenden.

Wenn ein Delegat erstellt wird, um eine Instanzmethode zu umschließen, verweist der Delegat sowohl auf die Instanz als auch auf die Methode. Ein Delegat hat keine Kenntnis über den Instanztyp, abgesehen von der Methode, die er umschließt. Eine Stellvertretung kann auf einen beliebigen Objekttyp verweisen, solange eine Methode für dieses Objekt vorhanden ist, die der Stellvertretungssignatur entspricht. Wenn ein Delegat erstellt wird, um eine statische Methode zu umhüllen, verweist er nur auf die Methode. Berücksichtigen Sie die folgenden Deklarationen:

public class MethodClass
{
    public void Method1(string message) { }
    public void Method2(string message) { }
}

Zusammen mit den zuvor gezeigten statischen DelegateMethod Methoden verfügen wir nun über drei Methoden, die Sie in eine Del Instanz umschließen können.

Ein Delegat kann mehr als eine Methode aufrufen, die als Multicasting bezeichnet wird. Um der Liste an Methoden des Delegaten, sprich der Aufrufliste, eine weitere Methode hinzuzufügen, müssen lediglich zwei Delegaten mithilfe der Additions- oder Additionszuweisungsoperatoren ('+' oder '+=') hinzugefügt werden. Beispiel:

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;

Dies allMethodsDelegate enthält drei Methoden in der Aufrufliste –Method1Method2 und DelegateMethod. Die ursprünglichen drei Delegierten, d1, d2, und d3, bleiben unverändert. Wenn allMethodsDelegate aufgerufen wird, werden alle drei Methoden in der angegebenen Reihenfolge aufgerufen. Wenn der Delegat Referenzparameter verwendet, wird der Verweis sequenziell an jede der drei Methoden übergeben, und alle Änderungen nach einer Methode sind für die nächste Methode sichtbar. Wenn eine der Methoden eine Ausnahme auslöst, die nicht innerhalb der Methode abgefangen wird, wird diese Ausnahme an den Aufrufer des Delegaten weitergegeben. In der Aufrufliste werden keine nachfolgenden Methoden aufgerufen. Wenn der Delegat über einen Rückgabewert und/oder ausgabeparameter verfügt, gibt er den Rückgabewert und die Parameter der letzten aufgerufenen Methode zurück. Um eine Methode aus der Aufrufliste zu entfernen, verwenden Sie die Subtraktions- oder Subtraktionszuweisungsoperatoren (- oder -=). Beispiel:

//remove Method1
allMethodsDelegate -= d1;

// copy AllMethodsDelegate while removing d2
Callback oneMethodDelegate = (allMethodsDelegate - d2)!;

Da Delegatentypen von System.Delegateabgeleitet werden, können die von dieser Klasse definierten Methoden und Eigenschaften für den Delegaten aufgerufen werden. Um beispielsweise die Anzahl der Methoden in der Aufrufliste eines Delegaten zu finden, können Sie Folgendes schreiben:

int invocationCount = d1.GetInvocationList().GetLength(0);

Delegaten mit mehr als einer Methode in der Aufrufliste werden von MulticastDelegate, einer Unterklasse von System.Delegate, abgeleitet. Der vorangehende Code funktioniert in beiden Fällen, da beide Klassen GetInvocationList unterstützt werden.

Multicastdelegaten werden ausgiebig bei der Ereignisbehandlung verwendet. Ereignisquellobjekte senden Ereignisbenachrichtigungen an Empfängerobjekte, die für den Empfang dieses Ereignisses registriert sind. Um sich für ein Ereignis zu registrieren, erstellt der Empfänger eine Methode zur Behandlung des Ereignisses, dann erstellt er 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 für den Empfänger auf und liefert die Ereignisdaten. Die Ereignisquelle definiert den Delegatentyp für ein bestimmtes Ereignis. Weitere Informationen finden Sie unter "Ereignisse".

Beim Vergleichen von zwei unterschiedlichen zugewiesenen Typen zur Kompilierzeit kommt es zu einem Kompilierungsfehler. Wenn die Delegateninstanzen statisch vom Typ System.Delegatesind, ist der Vergleich zulässig, gibt aber zur Laufzeit "false" zurück. Beispiel:

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);
}

Siehe auch