2010-10-07 18 views
29

Ich hasse EventHandler. Ich hasse es, dass ich die sender casten muss, wenn ich damit etwas anfangen will. Ich hasse es, dass ich eine neue Klasse erstellen muss, die von EventArgs erbt, um EventHandler<T> zu verwenden.Warum * sollten * Wir verwenden EventHandler

Ich habe immer gesagt, dass EventHandler ist die Tradition und blah, blah ... was auch immer. Aber ich kann keinen Grund finden, warum dieses Dogma immer noch existiert.

Gibt es einen Grund, warum es eine schlechte Idee, einen neuen Delegaten wäre zu machen:

delegate void EventHandler<TSender, T>(TSender sender, T args); 

Auf diese Weise wird die sender typsicher, und ich kann das Heck ich als Argumente (einschließlich benutzerdefinierte passieren, was auch immer wollen EventArgs wenn ich es wünsche).

+0

Dann können Sie auch nur Aktion als Ihr Delegierter verwenden. –

+0

Ja sehr wahr, also werde ich meine Frage erweitern: warum nicht Action ? – RichK

Antwort

24

Es gibt tatsächlich einen guten Grund dafür, dass das zweite Argument von EventArgs abgeleitet werden muss, wenn Ihr vollständig vertrauenswürdiger Code Drittanbietercode als teilweise vertrauenswürdig hostet.

Da der Rückruf zum Event-Handling-Delegaten im Kontext des Raise-Codes und nicht des Drittanbieter-Codes erfolgt, kann bösartiger Code von Drittanbietern eine privilegierte Systemoperation als Event-Handler und somit potenziell hinzufügen Führen Sie eine Eskalation der Zugriffsverletzung aus, indem Sie in Ihrem voll vertrauenswürdigen Kontext Code ausführen, dessen teilweise vertrauenswürdiger Kontext nicht ausgeführt werden konnte.

Wenn Sie beispielsweise einen Handler als Typ int -> void deklarieren, könnte der Code des Drittanbieters YourEvent += Enviroment.Exit(-1) in die Warteschlange stellen und Sie haben den Prozess unbeabsichtigt beendet. Dies würde natürlich zu einem leicht zu erkennenden Problem führen, aber es gibt weit mehr bösartige APIs, die in die Warteschlange eingereiht werden könnten, um andere Dinge zu tun.

Wenn die Signatur (object, EventArgs) -> void ist, dann gibt es keine privilegierten Operationen im Framework, die in die Warteschlange eingereiht werden können, weil keine von ihnen mit dieser Signatur kompatibel sind. Es ist Teil der Überprüfung des Sicherheitscodes im Framework, um dies zu gewährleisten (leider kann ich die Quelle, wo ich das lese, nicht finden).

Unter bestimmten Umständen gibt es daher berechtigte Sicherheitsbedenken, warum Sie das Standardmuster verwenden sollten. Wenn Sie sich 100% ig sicher sind, dass Ihr Code unter diesen Umständen niemals verwendet wird, dann ist die Ereignissignaturrichtlinie nicht so wichtig (abgesehen von anderen Entwicklern, die WTF denken), aber wenn es dann sein sollte, sollten Sie es befolgen.

+2

+1 Wow. Netter Post. Dies ist die Art von Posts, die mich dazu bringen, zu SO zurückzukehren. – NotMe

+0

Sehr, sehr interessant. Ich liebe es zu wissen, ob dies im ursprünglichen Design oder Konvention fiel oder Verwendung. –

+1

Obwohl dies eine gültige Antwort mit dem aktuellen Stand der Dinge ist, scheint es viel besser zu sein, wenn Code, der nicht Exit aufrufen sollte (oder ihn durchgeben soll) nicht einmal in der Lage war, auf Exit zuzugreifen Ort. –

9

Es gibt keinen Grund, es als seine angenommene .net Konvention zu verwenden und jeder, der Ihren Code liest, sollte es ziemlich leicht verstehen. Dafür ist es ein guter Grund.

Es ist jedoch Ihr Code und Sie können entscheiden, was am besten für Sie ist. Natürlich, wenn Sie mit dem fcl interagieren, müssen Sie es mit Event-Handlern tun.

+0

Ich stimme zu, es ist akzeptiert, dass jeder C# -Coder erkennen würde. –

+6

Das heißt, ein stark typisierter Delegierter würde auch erkannt werden :) –

+0

Ich sehe nicht, warum Entwickler durch den OP-Code verwirrt werden würden. Allerdings +1 für das Offensichtliche: Es ist sein Code zu tun, wie er will. – NotMe

0

Wie Preet Sangha sagte, wäre der Grund, warum solch ein Delegierter erstellt werden würde, eine schlechte Idee, dass andere Entwickler verwirrt sein könnten, warum Sie es auf diese Weise tun.

Mit EventHandler Delegaten ist ein Leitfaden hier vorgestellt: http://msdn.microsoft.com/en-us/library/ms229011.aspx

+5

Sie könnten jedoch argumentieren, dass, wenn Sie sagen, "Aktion <...>" als Ihre Event-Handler ist genug, um ein Teammitglied zu verwirren, Ihr Team hat bereits größere Probleme. ;) – jalf

+0

Ich habe seit 20 Jahren programmiert, die letzten 10 Jahre in C# und es würde mich verwirren, aber dann scheint das Ziel der meisten fortgeschrittenen Geschäfte heute zu sein, die kompliziertesten Designs zu verwenden, nicht einfache Ansätze zu verwenden. –

+0

6 Jahre sind vergangen, seit ich diese Antwort gepostet habe und ich bleibe total bei meiner Aussage. Es gibt eine Menge unerfahrener Entwickler, einige Entwickler, die die Sprache gewechselt haben, andere noch, aber sie werden immer noch in Projekten gebraucht und so weiter Menschen auf der Erde. Sicher ist es das Beste in einer Firma zu arbeiten, die nur die Crème de la Crème anstellt, aber in Wirklichkeit ist es besser zu erwarten, dass jemand durch solche Dinge verwirrt wird. Selbst erfahrene Leute könnten. Und das ultimative Ziel sollte die Bereitschaft des Codes sein. – prostynick

6

I Action<...> Typen als Event-Handler häufig verwenden - wenn Sie (oder einen Designer), die speziell EventHandler erfordert nicht mit anderem Code Interop müssen, gibt es kein Grund, es zu benutzen.

2

Nun, all das Casting ist ungewöhnlich, der Client-Code weiß oft schon, wer der Sender ist, weil es das Ereignis explizit für nur ein Objekt abonniert hat. Das Teilen von Ereignishandlern ist ziemlich selten. Wenn ein gemeinsames Verhalten wünschenswert ist, besteht der bessere Ansatz darin, von der Klasse abzuleiten und die OnXxxx-Methode zu überschreiben. Sie kümmern sich dann nicht mehr um Absender, Sie haben diese.

Lösen Sie Ihr Problem jedoch trivial, indem Sie in Ihrer benutzerdefinierten EventArgs-abgeleiteten Klasse einen typsicheren Verweis auf den Absender einfügen.

+1

Ich stimme dir nicht zu. zum Beispiel Client-Code kann nur einen Handler auf Array von Objekten haben. – void

+0

Hmya, das ist "Märchen selten". –

2

Ich stimme Ihnen zu, die Konvention ist dumm und/oder antiquiert. Tun Sie es richtig, mit der richtigen Typsicherheit und Generika.

Es kommt die ganze Zeit, dass Sie eine Aufgabe zu tun haben, und Sie können dem Weg folgen, wie der letzte Typ es getan hat oder es auf eine andere Art und Weise tun, von der Sie denken, dass es wahrscheinlich besser ist.

Die erste Wahl wird normalerweise gewählt - machen Sie es genauso wie den letzten, und Sie werden nicht in Schwierigkeiten geraten. Aber die zweite Wahl ist, was Software auf lange Sicht verbessert. (Oder zumindest kann es es verbessern, wenn Sie Recht haben, dass Ihr Weg besser ist! :))

Verwandte Themen