Freigeben über


Unterscheidung zwischen Delegaten und Ereignissen

Vorhergehend

Entwickler, die die .NET-Plattform noch nicht kennen, haben oft mit der Entscheidung zwischen einem Entwurf auf der Grundlage von delegates und einem Entwurf auf der Grundlage von events zu kämpfen. Die Auswahl von Delegierten oder Ereignissen ist häufig schwierig, da die beiden sprachlichen Merkmale ähnlich sind. Ereignisse werden sogar mithilfe der Sprachunterstützung für Stellvertretungen erstellt. Eine Ereignishandlerdeklaration deklariert einen Delegatentyp.

Beide bieten ein spätes Bindungsszenario: Sie ermöglichen Szenarien, in denen eine Komponente kommuniziert, indem eine Methode aufgerufen wird, die zur Laufzeit nur bekannt ist. Sie unterstützen sowohl einzelne als auch mehrere Abonnentenmethoden. Sie werden auf diese Begriffe möglicherweise im Zusammenhang mit Unicast- und Multicast-Unterstützung stoßen. Beide unterstützen ähnliche Syntax zum Hinzufügen und Entfernen von Handlern. Zum Schluss verwenden das Auslösen eines Ereignisses und das Aufrufen eines Delegaten genau dieselbe Methodenaufrufsyntax. Sie unterstützen sogar die gleiche Invoke() Methodensyntax für die Verwendung mit dem ?. Operator.

Bei all diesen Ähnlichkeiten ist es leicht, Probleme zu haben, zu entscheiden, wann welche verwendet werden sollte.

Das Abhören von Ereignissen ist optional.

Der wichtigste Aspekt bei der Bestimmung, welches Sprachmerkmal verwendet werden soll, ist, ob ein verbundener Abonnent vorhanden sein muss. Wenn Ihr Code den vom Abonnenten bereitgestellten Code aufrufen muss, sollten Sie ein Design basierend auf Delegaten verwenden, wenn Sie einen Rückruf implementieren müssen. Wenn Ihr Code ihre gesamte Arbeit abschließen kann, ohne Abonnenten aufzurufen, sollten Sie ein Design basierend auf Ereignissen verwenden.

Betrachten Sie die Beispiele, die in diesem Abschnitt erstellt wurden. Der von Ihnen verwendete List.Sort() Code muss über eine Vergleichsfunktion verfügen, um die Elemente ordnungsgemäß zu sortieren. LINQ-Abfragen müssen mit Delegaten bereitgestellt werden, um zu bestimmen, welche Elemente zurückgeben werden sollen. Beide haben ein Design verwendet, das mit Stellvertretungen erstellt wurde.

Betrachten Sie das Progress Ereignis. Er meldet den Fortschritt eines Vorgangs. Die Aufgabe wird fortgesetzt, unabhängig davon, ob listener vorhanden sind. Das FileSearcher ist ein weiteres Beispiel. Es würde weiterhin alle gesuchten Dateien suchen und finden, auch ohne angefügte Ereignisabonnenten. UX-Steuerelemente funktionieren weiterhin ordnungsgemäß, auch wenn keine Abonnenten die Ereignisse überwachen. Beide verwenden Designs, die auf Ereignissen basieren.

Rückgabewerte erfordern Delegaten

Ein weiterer Aspekt ist der Methodenprototyp, den Sie für Ihre Delegiertenmethode verwenden möchten. Wie Sie gesehen haben, verfügen alle für Ereignisse verwendeten Delegaten über einen void-Rückgabetyp. Es gibt Idiome zum Erstellen von Ereignishandlern, die Informationen zurück an Ereignisquellen übergeben, indem Eigenschaften des Ereignisargumentobjekts geändert werden. Während diese Idiome funktionieren, sind sie nicht so natürlich wie die Rückgabe eines Werts aus einer Methode.

Beachten Sie, dass diese beiden Heuristiken häufig vorhanden sein können: Wenn Ihre Delegatmethode einen Wert zurückgibt, wirkt sich dies auf irgendeine Weise auf den Algorithmus aus.

Privater Aufruf von Ereignissen

Andere Klassen als die Klassen, in denen ein Ereignis enthalten ist, können nur Ereignislistener hinzufügen und entfernen; nur die Klasse, die das Ereignis enthält, kann das Ereignis aufrufen. Ereignisse sind normalerweise öffentliche Klassenmember. Im Vergleich dazu werden Stellvertretungen häufig als Parameter übergeben und als private Klassenmitglieder gespeichert, wenn sie überhaupt gespeichert sind.

Ereignislistener haben häufig eine längere Lebensdauer

Die längere Lebensdauer der Ereignislistener ist eine eher schlechtere Begründung. Möglicherweise stellen Sie jedoch fest, dass ereignisbasierte Designs natürlicher sind, wenn die Ereignisquelle Ereignisse über einen längeren Zeitraum auslöst. Beispiele für ereignisbasiertes Design für UX-Steuerelemente auf vielen Systemen finden Sie. Sobald Sie ein Ereignis abonnieren, kann die Ereignisquelle Ereignisse während der gesamten Lebensdauer des Programms auslösen. (Sie können sich von Ereignissen abmelden, wenn Sie sie nicht mehr benötigen.)

Vergleichen Sie das mit vielen delegatbasierten Entwürfen, bei denen ein Delegat als Argument an eine Methode verwendet wird, und der Delegat wird nicht verwendet, nachdem diese Methode zurückgegeben wird.

Sorgfältig auswerten

Die oben genannten Überlegungen sind keine harten und schnellen Regeln. Stattdessen stellen sie Anleitungen dar, mit denen Sie entscheiden können, welche Wahl für Ihre jeweilige Verwendung am besten geeignet ist. Da sie ähnlich sind, können Sie sogar beide prototypen und überlegen, mit welchem es natürlicher zu arbeiten wäre. Beide behandeln Szenarios mit später Bindung gut. Verwenden Sie das Design, das Ihr Design am besten kommuniziert.