Bevorzugte Möglichkeit, Ereignisse zu deklarieren

14

Ich bin ziemlich zufrieden mit meinem Verständnis des .NET-Ereignismodells. Ich denke, ich könnte eine kleine Nuance des Systems missverstehen.

Als ich anfing, Events in meine Klassen aufzunehmen, habe ich die Standardmethode wie folgt verwendet:

public event EventHandler<MyEventArgs> MyEvent;

Dies bedeutete, dass alles, was das Ereignis abonniert, eine Methode wie die folgende benötigt:

void HandleThatEvent(object sender, MyEventArgs args){...}

Was nett ist, aber ich fand, dass ich mich selten um den Absender kümmern würde, so dass viele Methodensignaturen aufgebläht wurden.

Also habe ich meine eigenen Delegiertentypen deklariert

public delegate void MyEventHandler(SomeClass argument);

Was die Unordnung einschränkt, mir aber ein kleines Problem beim Schreiben von Handlern hinterlässt:

eventImplmentor.MyEvent += HandleThatEvent;
.
.
.
void HandleThatEvent(/*oh, um, what arguments does it take? Intellisense isn't telling me*/)

Also müsste ich zur Erklärung des Delegierten zurückkehren und nachsehen und sie dann zurückschreiben oder kompilieren und warten, bis sie mir mitgeteilt werden.

Also verwende ich stattdessen einfach eine Vorlage Action, Action<T>oder welche auch immer passt.

public event Action<SomeClass> MyEvent;

Damit ich über das Ereignis schweben und erfahren kann, welche Parameter es erwartet.

Meine Frage nach all dem: Gibt es eine bewährte Methode zum Deklarieren von Ereignissen in C #? Soll ich auf den EventHandler<T>Weg zurückgehen, oder ist das Action<T>akzeptabel?

Matt Ellen
quelle
Vergessen Sie nicht, sicherzustellen, dass der Handler lokal an den Ort kopiert wird, an dem Sie das Ereignis auslösen. Dies sollte aus Gründen der Threadsicherheit immer erfolgen.
Snoop
Sie können Ihre eigenen intelligenten, schlanken und typsicheren Ereignisse in gekapselten Code schreiben, aber alles, was Sie veröffentlichen, sollte dem Standardmuster folgen, oder es wird nur die Benutzer Ihrer Klasse verwirren (und anscheinend auch einige Tools).
Martin Maat

Antworten:

8

Für eine einfache interne Ereignisbehandlung gibt es solche, die einfach Actionoder verwenden Action<T>, wie Sie es vorschlagen. Ich neige dazu, das Standardmuster, einschließlich des Absenders, auch für interne Ereignisse zu verwenden, da Sie nie wissen, wann Sie später eine Klasse oder ein Ereignis verfügbar machen möchten, und ich möchte nicht die Strafe, die Ereignismethode nur umgestalten zu müssen, um dies zu erreichen es öffentlich.

Ich stimme Ihnen zu, dass die Signatur für die Ereignisbehandlung etwas schwerer ist, als es für einfache Szenarien sein sollte, aber sie ist gut für die inkrementelle Migration ausgelegt, da im Laufe der Zeit zusätzliche Ereignisargumente erforderlich werden könnten. Insgesamt würde ich mich an das Standardmuster halten, zumal Sie, wie Sie bereits bemerkt haben, nur dann eine ordnungsgemäße IntelliSense-Unterstützung erhalten, wenn Sie dies tun.

Für das, was es wert ist, habe ich mir etwas Zeit genommen und mir ein anderes Ereignisbehandlungsmuster ausgedacht : Ereignissignatur in .NET - Verwenden eines stark typisierten "Absenders"? . Das Ziel hier war nicht, den Absender zu entfernen, sondern ihn generisch als stark TSenderanstatt schwach als getippt zu kennzeichnen System.Object. Es funktioniert sehr gut; Wenn Sie dies tun, geht jedoch die IntelliSense-Unterstützung verloren, sodass ein unglücklicher Kompromiss besteht.

Insgesamt würde ich mich an das Standardmuster halten, aber es ist interessant, über potenziell bessere Möglichkeiten nachzudenken, um dies zu tun.

Mike Rosenblum
quelle
Vielen Dank, dass Sie mich auf Ihre SO-Frage hingewiesen haben. Es ist sehr interessant. Ich verstehe immer noch nicht, warum es so wichtig ist, dass der Absender obligatorisch ist. Die meiste Zeit ist mir der Absender egal. Ist es nur eine willkürliche MS-Regel?
Matt Ellen
Nein, natürlich können Sie Ihre Delegierten deklarieren, wie Sie möchten. Es ist eine .NET-Richtlinie, immer den Absender mit einzubeziehen, und das ist keine schlechte Idee.
Neil
@Neil: Ich verstehe, dass es manchmal nützlich ist, aber ich verstehe nicht die Politik, es immer zu tun - besonders, da MS Veranstaltungen auf ihre Weise empfehlen. Eines der Dinge, die ich an Events wirklich mag, ist die Fähigkeit, Klassen zu entkoppeln. Wenn ich das Objekt einbinde, wird es erneut gekoppelt. Wenn es nur eine Sache der CLS-Konformität ist, kann ich damit leben.
Matt Ellen
Es wird nur dann erneut gekoppelt, wenn Sie das Absenderobjekt verwenden. Andernfalls spielt es keine Rolle, was als Absenderwert angegeben wird, da Sie es nicht verwenden. Abhängigkeit besteht nur, wenn eine Abhängigkeit bestehen muss. Ich sehe, woher Sie kommen, und wenn der Absender eines Objekts von jedem Server auf dem Planeten aus dem gesamten Code verschwindet, würde ich nicht über Nacht wach bleiben.
Neil
Ja, Sie können "null" als Absender senden, wenn Sie dies wirklich möchten. Wenn Sie jedoch den Absender einbeziehen, kann der Ereignishandler selbst das Abonnement aufheben, wenn er dies wünscht. Insgesamt würde ich jedoch sagen, dass es in der Regel ziemlich wichtig ist, die Quelle des Ereignisses zu kennen.
Mike Rosenblum