Ich verstehe den Zweck von Ereignissen, insbesondere im Zusammenhang mit der Erstellung von Benutzeroberflächen. Ich denke, dies ist der Prototyp für die Erstellung eines Ereignisses:
public void EventName(object sender, EventArgs e);
Was machen Event-Handler, warum werden sie benötigt und wie erstelle ich einen?
c#
.net
events
event-handling
Levi Campbell
quelle
quelle
Antworten:
Um Ereignishandler zu verstehen, müssen Sie die Delegaten verstehen . In C # können Sie sich einen Delegaten als Zeiger (oder Referenz) auf eine Methode vorstellen. Dies ist nützlich, da der Zeiger als Wert übergeben werden kann.
Das zentrale Konzept eines Delegierten ist seine Unterschrift oder Form. Das ist (1) der Rückgabetyp und (2) die Eingabeargumente. Wenn wir beispielsweise einen Delegaten erstellen
void MyDelegate(object sender, EventArgs e)
, kann dieser nur auf Methoden verweisen, die zurückgebenvoid
, und einobject
und nehmenEventArgs
. Ein bisschen wie ein quadratisches Loch und ein quadratischer Stift. Wir sagen also, dass diese Methoden dieselbe Signatur oder Form haben wie der Delegat.Wenn wir also wissen, wie ein Verweis auf eine Methode erstellt wird, lassen Sie uns über den Zweck von Ereignissen nachdenken: Wir möchten, dass Code ausgeführt wird, wenn an einer anderen Stelle im System etwas passiert - oder "das Ereignis behandeln". Dazu erstellen wir spezielle Methoden für den Code, den wir ausführen möchten. Der Klebstoff zwischen dem Ereignis und den auszuführenden Methoden sind die Delegierten. Das Ereignis muss intern eine "Liste" von Zeigern auf die Methoden speichern, die beim Auslösen des Ereignisses aufgerufen werden sollen. * Um eine Methode aufrufen zu können, müssen wir natürlich wissen, welche Argumente an sie übergeben werden müssen! Wir verwenden den Delegaten als "Vertrag" zwischen der Veranstaltung und allen spezifischen Methoden, die aufgerufen werden.
Die Standardeinstellung
EventHandler
(und viele davon mögen sie) repräsentiert also eine bestimmte Form der Methode (wiederum void / object-EventArgs). Wenn Sie ein Ereignis deklarieren, geben Sie an, welche Methodenform (EventHandler) dieses Ereignis aufruft, indem Sie einen Delegaten angeben:(* Dies ist der Schlüssel zu Ereignissen in .NET und entfernt die "Magie" - ein Ereignis ist im Grunde genommen nur eine Liste von Methoden mit derselben "Form". Die Liste wird dort gespeichert, wo das Ereignis lebt. Wann Das Ereignis wird "ausgelöst", es ist wirklich nur "diese Liste von Methoden durchgehen und jede aufrufen, wobei diese Werte als Parameter verwendet werden". Das Zuweisen eines Ereignishandlers ist nur eine schönere und einfachere Möglichkeit, Ihre Methode zu dieser Liste von Methoden hinzuzufügen heißen).
quelle
C # kennt zwei Begriffe
delegate
undevent
. Beginnen wir mit dem ersten.Delegieren
A
delegate
ist eine Referenz auf eine Methode. So wie Sie einen Verweis auf eine Instanz erstellen können:Sie können einen Delegaten verwenden, um einen Verweis auf eine Methode zu erstellen:
Nachdem Sie diese Referenz auf eine Methode haben, können Sie die Methode über die Referenz aufrufen:
Aber warum würdest du? Sie können auch einfach
myFactory.GetInstance()
direkt anrufen . In diesem Fall können Sie. Es gibt jedoch viele Fälle, in denen Sie darüber nachdenken müssen, wo der Rest der Anwendung keine Kenntnisse habenmyFactory
oder anrufen sollmyFactory.GetInstance()
direkt .Ein offensichtlichste ist , wenn Sie ersetzen können , wollen
myFactory.GetInstance()
inmyOfflineFakeFactory.GetInstance()
von einem zentralen Ort (auch bekannt als Factory - Methode Mustern ).Fabrikmethodenmuster
Wenn Sie also eine
TheOtherClass
Klasse haben und diese verwenden müssenmyFactory.GetInstance()
, sieht der Code ohne Delegaten folgendermaßen aus (Sie müssenTheOtherClass
den Typ Ihrer Klasse angebenmyFactory
):Wenn Sie Delegaten verwenden möchten, müssen Sie den Typ meiner Fabrik nicht offenlegen:
Auf diese Weise können Sie einen Delegaten einer anderen Klasse zur Verwendung zuweisen, ohne Ihren Typ für sie verfügbar zu machen. Das einzige, was Sie verfügbar machen, ist die Signatur Ihrer Methode (wie viele Parameter Sie haben und so).
"Unterschrift meiner Methode", wo habe ich das vorher gehört? O ja, Schnittstellen !!! Schnittstellen beschreiben die Signatur einer ganzen Klasse. Stellen Sie sich Delegierte so vor, als würden sie die Signatur nur einer Methode beschreiben!
Ein weiterer großer Unterschied zwischen einer Schnittstelle und einem Delegaten besteht darin, dass Sie beim Schreiben Ihrer Klasse C # nicht sagen müssen, dass diese Methode diesen Delegatentyp implementiert. Bei Schnittstellen müssen Sie sagen "Diese Klasse implementiert diesen Typ einer Schnittstelle".
Ferner kann eine Delegatenreferenz (mit einigen Einschränkungen, siehe unten) mehrere Methoden (aufgerufen) referenzieren
MulticastDelegate
) . Dies bedeutet, dass beim Aufrufen des Delegaten mehrere explizit angehängte Methoden ausgeführt werden. Eine Objektreferenz kann immer nur auf ein Objekt verweisen.Die Einschränkungen für a
MulticastDelegate
bestehen darin, dass die Signatur (Methode / Delegat) keinen Rückgabewert (void
) und die Schlüsselwörter haben sollteout
undref
nicht in der Signatur verwendet wird. Natürlich können Sie nicht zwei Methoden aufrufen, die eine Nummer zurückgeben, und erwarten, dass sie dieselbe Nummer zurückgeben. Sobald die Signatur übereinstimmt, ist der Delegat automatisch einMulticastDelegate
.Veranstaltung
Ereignisse sind nur Eigenschaften (wie get; set; Eigenschaften für Instanzfelder), die das Abonnement für den Delegaten von anderen Objekten verfügbar machen. Diese Eigenschaften unterstützen get; set; jedoch nicht. Stattdessen unterstützen sie add; entfernen;
So können Sie haben:
Verwendung in der Benutzeroberfläche (WinForms, WPF, UWP usw.)
Jetzt wissen wir also, dass ein Delegat eine Referenz auf eine Methode ist und dass wir ein Ereignis haben können, um die Welt wissen zu lassen, dass sie uns ihre Methoden geben können, auf die von unserem Delegaten verwiesen werden kann, und wir sind dann eine UI-Schaltfläche: wir kann jeden, der daran interessiert ist, ob ich angeklickt wurde, bitten, seine Methode bei uns zu registrieren (über das Ereignis, das wir ausgesetzt haben). Wir können alle Methoden anwenden, die uns gegeben wurden, und sie von unserem Delegierten referenzieren. Und dann warten wir und warten ... bis ein Benutzer kommt und auf diese Schaltfläche klickt, dann haben wir genug Grund, den Delegaten aufzurufen. Und weil der Delegat auf alle uns gegebenen Methoden verweist, werden alle diese Methoden aufgerufen. Wir wissen nicht, was diese Methoden tun, und wir wissen auch nicht, welche Klasse diese Methoden implementiert. Wir kümmern uns nur darum, dass jemand daran interessiert war, dass wir angeklickt werden.
Java
Sprachen wie Java haben keine Delegierten. Sie verwenden stattdessen Schnittstellen. Sie bitten jeden, der daran interessiert ist, dass wir angeklickt werden, eine bestimmte Schnittstelle zu implementieren (mit einer bestimmten Methode, die wir aufrufen können), und geben dann die gesamte Instanz an, die die Schnittstelle implementiert. Wir führen eine Liste aller Objekte, die diese Schnittstelle implementieren, und können ihre "bestimmte Methode, die wir aufrufen können" aufrufen, wenn wir darauf klicken.
quelle
event
ist nur Syntax Zucker, nicht mehr.Das ist eigentlich die Deklaration für einen Ereignishandler - eine Methode, die aufgerufen wird, wenn ein Ereignis ausgelöst wird. Um ein Ereignis zu erstellen, schreiben Sie Folgendes:
Und dann können Sie die Veranstaltung folgendermaßen abonnieren:
Mit OnMyEvent () wie folgt definiert:
Immer wenn es
Foo
losgehtMyEvent
, wird IhrOnMyEvent
Handler gerufen.Sie müssen nicht immer eine Instanz von
EventArgs
als zweiten Parameter verwenden. Wenn Sie zusätzliche Informationen einschließen möchten, können Sie eine Klasse verwenden, die vonEventArgs
(EventArgs
ist die Basis gemäß Konvention) abgeleitet ist. Wenn Sie sich beispielsweise einige derControl
in WinForms oderFrameworkElement
in WPF definierten Ereignisse ansehen , sehen Sie Beispiele für Ereignisse, die zusätzliche Informationen an die Ereignishandler übergeben.quelle
OnXXX
Namensmuster für Ihren Event-Handler nicht zu verwenden. (Dummerweise bedeutet OnXXX in MFC "Handle XXX" und in .net "XXX erhöhen". Daher ist seine Bedeutung jetzt unklar und verwirrend - siehe diesen Beitrag für Details ). Bevorzugte Namen wären dasRaiseXXX
Auslösen von Ereignissen und /HandleXXX
oderSender_XXX
für Ereignishandler.Hier ist ein Codebeispiel, das helfen kann:
quelle
OnMaximum?.Invoke(this,new MyEventArgs("you've entered..."));
Nur um die vorhandenen großartigen Antworten hier zu ergänzen - aufbauend auf dem Code in der akzeptierten, der
delegate void MyEventHandler(string foo)
...Da der Compiler den Delegatentyp des SomethingHappened- Ereignisses kennt , gilt Folgendes:
Ist völlig gleichbedeutend mit:
Und Handler kann auch nicht registrierte mit
-=
wie folgt aus :Der Vollständigkeit halber kann das Auslösen des Ereignisses nur in der Klasse durchgeführt werden, der das Ereignis gehört:
Der Thread-lokale Kopie des Handlers ist notwendig , um sicherzustellen , dass der Aufruf ist Thread-sicher - sonst könnte ein Thread gehen und austragen der letzten Prozedur für das Ereignis sofort , nachdem wir überprüft , ob es war
null
, und wir hätten einen „Spaß“NullReferenceException
gibt .C # 6 führte eine schöne kurze Hand für dieses Muster ein. Es verwendet den Null-Ausbreitungsoperator.
quelle
Mein Verständnis der Ereignisse ist;
Delegieren:
Eine Variable, die einen Verweis auf die auszuführenden Methoden enthält. Dies ermöglicht es, Methoden wie eine Variable weiterzugeben.
Schritte zum Erstellen und Aufrufen des Ereignisses:
Die Veranstaltung ist eine Instanz eines Delegaten
Da ein Ereignis eine Instanz eines Delegaten ist, müssen wir zuerst den Delegaten definieren.
Weisen Sie die Methode (n) zu, die ausgeführt werden sollen, wenn das Ereignis ausgelöst wird ( Aufruf des Delegaten )
Ereignis auslösen ( Delegierten anrufen )
Beispiel:
quelle
Herausgeber: Wo die Ereignisse stattfinden. Der Herausgeber sollte angeben, welchen Delegaten die Klasse verwendet, und die erforderlichen Argumente generieren, diese Argumente und sich selbst an den Delegaten übergeben.
Teilnehmer: Wo die Antwort erfolgt. Der Abonnent sollte Methoden angeben, um auf Ereignisse zu reagieren. Diese Methoden sollten die gleichen Argumente wie der Delegat verwenden. Der Abonnent fügt diese Methode dann dem Delegierten des Herausgebers hinzu.
Wenn das Ereignis im Herausgeber auftritt, erhält der Delegat daher einige Ereignisargumente (Daten usw.), aber der Herausgeber hat keine Ahnung, was mit all diesen Daten geschehen wird. Abonnenten können Methoden in ihrer eigenen Klasse erstellen, um auf Ereignisse in der Publisher-Klasse zu reagieren, sodass Abonnenten auf Publisher-Ereignisse reagieren können.
quelle
quelle
Ich stimme KE50 zu, außer dass ich das Schlüsselwort 'event' als Alias für 'ActionCollection' betrachte, da das Ereignis eine Sammlung von auszuführenden Aktionen enthält (dh den Delegaten).
quelle
Tolle technische Antworten in der Post! Ich habe technisch nichts hinzuzufügen.
Einer der Hauptgründe, warum neue Funktionen in Sprachen und Software im Allgemeinen erscheinen, ist Marketing oder Unternehmenspolitik! :-) Das darf nicht unterschätzt werden!
Ich denke, dies gilt in gewissem Umfang auch für Delegierte und Veranstaltungen! Ich finde sie nützlich und füge der C # -Sprache einen Mehrwert hinzu, aber andererseits hat die Java-Sprache beschlossen, sie nicht zu verwenden! Sie haben entschieden, dass alles, was Sie mit Delegierten lösen, bereits mit vorhandenen Funktionen der Sprache gelöst werden kann, z. B. Schnittstellen, z
Um 2001 herum veröffentlichte Microsoft das .NET-Framework und die C # -Sprache als Konkurrenzlösung für Java. Es war also gut, NEUE FUNKTIONEN zu haben, die Java nicht hat.
quelle
Ich habe kürzlich ein Beispiel für die Verwendung von Ereignissen in c # erstellt und es in meinem Blog veröffentlicht. Ich habe versucht, es anhand eines sehr einfachen Beispiels so klar wie möglich zu machen. Falls es jemandem helfen könnte, hier ist es: http://www.konsfik.com/using-events-in-csharp/
Es enthält Beschreibung und Quellcode (mit vielen Kommentaren) und konzentriert sich hauptsächlich auf die ordnungsgemäße (vorlagenähnliche) Verwendung von Ereignissen und Ereignishandlern.
Einige wichtige Punkte sind:
Ereignisse sind wie "Untertypen von Delegierten", nur eingeschränkter (auf gute Weise). Tatsächlich enthält die Deklaration eines Ereignisses immer einen Delegaten (EventHandler sind eine Art Delegat).
Ereignishandler sind bestimmte Arten von Delegaten (Sie können sie als Vorlage betrachten), die den Benutzer dazu zwingen, Ereignisse mit einer bestimmten "Signatur" zu erstellen. Die Signatur hat das folgende Format: (Objektabsender, EventArgs-Ereignisargumente).
Sie können Ihre eigene Unterklasse von EventArgs erstellen, um alle Arten von Informationen aufzunehmen, die das Ereignis übermitteln muss. Es ist nicht erforderlich, EventHandler zu verwenden, wenn Ereignisse verwendet werden. Sie können sie vollständig überspringen und an ihrer Stelle Ihre eigene Art von Delegierten einsetzen.
Ein wesentlicher Unterschied zwischen der Verwendung von Ereignissen und Delegaten besteht darin, dass Ereignisse nur innerhalb der Klasse aufgerufen werden können, in der sie deklariert wurden, obwohl sie möglicherweise als öffentlich deklariert sind. Dies ist eine sehr wichtige Unterscheidung, da Ihre Ereignisse dadurch sichtbar gemacht werden können, dass sie mit externen Methoden "verbunden" sind, während sie gleichzeitig vor "externem Missbrauch" geschützt sind.
quelle
Eine andere Sache, die Sie wissen sollten , in einigen Fällen müssen Sie die Delegaten / Ereignisse verwenden, wenn Sie ein geringes Maß an Kopplung benötigen !
Wenn Sie möchten , eine Komponente in mehrere in Anwendung verwenden , müssen Sie eine Komponente mit niedrigem Pegel zu koppeln und das spezifische machen unbeteiligt LOGIC muß delegiert werden OUTSIDE Ihrer Komponente! Dies stellt sicher, dass Sie ein entkoppeltes System und einen saubereren Code haben.
Im SOLID- Prinzip ist dies das " D " ( D. Ependenz-Inversionsprinzip).
Auch bekannt als " IoC ", Inversion of Control .
Sie können " IoC " mit Events, Delegates und DI erstellen (Dependency Injection) erstellen.
Es ist einfach, auf eine Methode in einer untergeordneten Klasse zuzugreifen. Es ist jedoch schwieriger, von einem Kind aus auf eine Methode in einer Elternklasse zuzugreifen. Sie müssen den Elternverweis an das Kind weitergeben! (oder DI mit Schnittstelle verwenden)
Mit Delegierten / Veranstaltungen können wir ohne Bezugnahme vom Kind zum Elternteil kommunizieren!
In diesem Diagramm oben verwende ich Delegate / Event nicht und die übergeordnete Komponente B muss eine Referenz der übergeordneten Komponente A haben, um die nicht betroffene Geschäftslogik in Methode A auszuführen (hohe Kopplungsstufe).
Bei diesem Ansatz müsste ich alle Referenzen aller Komponenten einfügen, die Komponente B verwenden! :(
In diesem Diagramm oben verwende ich Delegate / Event und die Komponente B muss A nicht kennen. (Geringe Kopplung)
Und Sie können Ihre Komponente B überall in Ihrer Anwendung verwenden !
quelle