2010-02-17 8 views
52

Ich habe Entwickler gesehen, die die folgenden Codes ganz alternativ verwenden. Was ist der genaue Unterschied zwischen diesen und welchen Normen? Sind sie gleich, wie Action und Func<T> ein Delegierter ist auch:Aktion <T> vs Delegat Ereignis

public event Action<EmployeeEventAgs> OnLeave; 
public void Leave() 
{ 
    OnLeave(new EmployeeEventAgs(this.ID)); 
} 

VS

public delegate void GoOnLeave(EmployeeEventAgs e); 
public event GoOnLeave OnLeave; 
public void Leave() 
{ 
    OnLeave(new EmployeeEventAgs(this.ID)); 
} 

Antwort

48

Fwiw, kein Beispiel verwendet Standard-.NET-Konventionen. Die EventHandler<T> generic sollte das Ereignis deklarieren:

public event EventHandler<EmployeeEventArgs> Leave; 

Die „On“ Präfix sollte für eine geschützte Methode reserviert werden, die das Ereignis auslöst:

protected virtual void OnLeave(EmployeeEventArgs e) { 
    var handler = Leave; 
    if (handler != null) handler(this, e); 
} 

Sie nicht haben es, dies zu tun so, aber jeder wird sofort das Muster erkennen, Ihren Code verstehen und wissen, wie man es benutzt und anpasst.

Und es hat den großen Vorteil, nicht gezwungen zu sein, zwischen einer benutzerdefinierten Delegiertenerklärung zu wählen und Action<>, EventHandler<> ist der beste Weg. Welches beantwortet deine Frage.

+29

Das ist ein guter Ratschlag, aber ich glaube nicht, dass er die Frage beantwortet –

+2

Haben Sie den 'Leave' -Handler als Delegat deklariert, anstatt: public __event__ EventHandler <> ... absichtlich? Das 'event'-Schlüsselwort ist ein Spiel, das sich verändert, wenn Sie mit der Klasse arbeiten, die das Ereignis ausgibt, denn ohne sie könnte man einfach die gesamte Ereignisauflistung löschen, indem Sie' obj.Leave = someHandler' statt 'obj.Leave + = someHandler verwenden ' –

+3

Nein, das war ein Fehler. Niemand hat in drei Jahren bemerkt :) Danke! –

4

Ja, Aktion und Func sind einfach Bequemlichkeit Delegierten, die in der 3,5 clr definiert wurden.

Aktion, Func und Lambdas sind alles nur syntaktische Zucker und Bequemlichkeit für die Verwendung von Delegierten.

Es gibt nichts Magisches an ihnen. Mehrere Leute haben einfache 2.0-Addon-Bibliotheken geschrieben, um diese Funktionalität zu 2.0-Code hinzuzufügen.

20

Action<T> ist genau das gleiche wie delegate void ... (T t)

Func<T> ist genau das gleiche wie delegate T ...()

+0

Nicht * genau das gleiche * ... sie haben die gleiche Signatur, aber sie sind nicht Zuordnung kompatibel (die IMHO ist sehr bedauerlich ...) –

+4

macht das sie nicht genau das gleiche?Sind X und Y hier anders: öffentlicher Delegierter void X (T t); öffentlicher Delegierter void Y (T t); Sie können keine anderen zuweisen. – pdr

3

You may want to look here, zu sehen, was der Compiler tatsächlich für die Aktion erzeugt die beste Beschreibung ist. Es gibt keinen funktionalen Unterschied in dem, was Sie geschrieben haben, nur eine kürzere, bequemere Syntax.

3

Im Allgemeinen sind sie gleichwertig. Aber im Rahmen eines Delegaten für den Typ eines Ereignisses verwenden, ist die Konvention Eventhandler zu verwenden (wobei T erbt EventArgs):

public event EventHandler<EmployeeEventArgs> Left; 

public void Leave() 
{ 
    OnLeft(this.ID); 
} 

protected virtual void OnLeft(int id) 
{ 
    if (Left != null) { 
     Left(new EmployeeEventArgs(id)); 
    } 
} 
0

Sie haben diese Aktion schreiben können und Func generische Delegaten selbst, aber da sie Im Allgemeinen sind sie nützlich, sie haben sie für dich geschrieben und in .Net-Bibliotheken gesteckt.

20

Die beiden folgenden Codezeilen sind nahezu äquivalent:

public event Action<EmployeeEventAgs> Leave; 

im Gegensatz zu:

public event EventHandler<EmployeeEventAgs> Leave; 

Der Unterschied liegt in der Signatur des Verfahrens Ereignisbehandlungsroutine. Wenn Sie den ersten Ansatz mit der Aktion verwenden, könnten Sie haben:

public void LeaveHandler(EmployeeEventAgs e) { ... } 

und dann diese:

obj.Leave += LeaveHandler; 

Mit dem zweiten Ansatz, die Unterzeichnung der LeaveHandler Bedürfnisse anders sein:

public void LeaveHandler(object sender, EmployeeEventAgs e) { ... } 

Es ist sehr wichtig zu bemerken th In beiden Fällen ist das Schlüsselwort event vorhanden. Ein Ereignis, das über das Schlüsselwort event explizit als solches deklariert wird, ist kein Feld der Klasse mehr. Stattdessen wird es eine Ereigniseigenschaft. Die Ereigniseigenschaften ähneln den regulären Eigenschaften, außer dass sie keine get oder set Accessoren haben. Der Compiler erlaubt es, sie nur auf der linken Seite einer += und -= Zuweisung zu verwenden (Hinzufügen oder Entfernen eines Ereignishandlers). Es gibt keine Möglichkeit, überschreiben die bereits zugewiesenen Ereignishandler oder rufen Sie das Ereignis außerhalb der Klasse, die es deklariert.

Wenn das Ereignis Schlüsselwort wurde in beiden Beispielen fehlt, könnte man ohne Fehler oder Warnung die folgenden Operationen ausführen:

obj.Leave = LeaveHandler; 

, die wird löschen Sie alle registrierten Handler und ersetzen sie die LeaveHandler Withe.

Darüber hinaus können Sie auch diesen Anruf durchführen:

obj.Leave(new EmployeeEventAgs()); 

Die beiden oben genannten Beispiele gelten als ein anti-Muster, wenn Sie beabsichtigen, ein Ereignis zu erstellen. Ein Ereignis sollte nur durch das Objekt des Eigentümers aufgerufen werden und sollte nicht zulassen, nicht rückverfolgbar Entfernung von Abonnenten. Das Schlüsselwort event ist das programmatische Konstrukt von .NET, das Ihnen hilft, bei der korrekten Verwendung von Ereignissen zu bleiben.

Ich denke, dass viele Leute bleiben mit dem EventHandler Ansatz, weil es eher unwahrscheinlich ist, ein EventHandler ohne das Schlüsselwort event zu verwenden. Aktionen haben einen größeren Anwendungsbereich, sie sehen nicht so natürlich aus, wenn sie als Ereignisse verwendet werden. Letzteres ist natürlich eine persönliche Meinung, da der Event-Handler-Ansatz in meinen Programmierpraktiken wahrscheinlich zu stark verdrahtet ist. Wenn jedoch Aktionen richtig verwendet werden, ist es kein Verbrechen, sie für Ereignisse zu verwenden.

+1

+1 für die detaillierte Erklärung. – Joel