2010-02-17 13 views
52

He visto a los desarrolladores usando los siguientes códigos alternativamente. ¿Cuál es la diferencia exacta entre estos y cuáles se ajustan al estándar? Son ellos mismos, como Action y Func<T> es un delegado así:Acción <T> vs evento de delegado

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)); 
} 

Respuesta

48

Fwiw, ninguno de los dos ejemplos utiliza convenciones .NET estándar. El EventHandler<T> genérico debe declarar el evento:

public event EventHandler<EmployeeEventArgs> Leave; 

El prefijo "on" debe reservarse para un método protegido que genera el evento:

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

No tienen que hacerlo de esta manera, pero cualquiera reconocerá instantáneamente el patrón, entenderá su código y sabrá cómo usarlo y personalizarlo.

Y tiene la gran ventaja de no ser forzado a elegir entre una declaración de delegado personalizada y Action<>, EventHandler<> es la mejor manera. Que responde a tu pregunta

+29

Este es un buen consejo, pero no creo que responda la pregunta –

+2

¿Declaraste el manejador 'Leave' como un delegado, en lugar de: public __event__ EventHandler <> ... a propósito? La palabra clave 'event' cambia bastante las reglas de juego cuando trabajas con la clase exponiendo el evento, ya que sin él uno simplemente podría borrar toda la colección de eventos usando' obj.Leave = someHandler' en lugar de 'obj.Leave + = someHandler ' –

+3

No, eso fue un error. Nadie se dio cuenta en tres años :) ¡Gracias! –

4

Sí, Acción y Func son delegados simplemente de conveniencia que se han definido en el 3,5 CLR.

Acción, Func y lambdas son solo azúcar sintáctico y conveniencia para el uso de delegados.

No hay nada mágico en ellos. Varias personas han escrito simples bibliotecas de complementos 2.0 para agregar esta funcionalidad al código 2.0.

20

Action<T> es exactamente el mismo que delegate void ... (T t)

Func<T> es exactamente el mismo que delegate T ...()

+0

No * exactamente lo mismo * ... tienen la misma firma, pero no son compatibles con la asignación (lo que en mi humilde opinión es muy desafortunado ...) –

+4

¿Eso los hace no exactamente lo mismo?Son X e Y diferentes aquí: delegado público void X (T t); delegado público void Y (T t); No puede asignar uno a otro. – pdr

3

You may want to look here, viendo lo que el compilador genera realmente de Acción es la mejor descripción. No hay diferencia funcional en lo que escribiste, solo una sintaxis más corta y más conveniente.

3

En general, son equivalentes. Pero en el contexto de la utilización de un delegado para el tipo de un evento, la convención es utilizar manejador de sucesos (donde T hereda 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

Se podría haber escrito estas Acción y genéricos Func usted mismo los delegados, pero ya que En general, son útiles. Te los escribieron y los metieron en las bibliotecas de .Net.

20

Los siguientes dos líneas de código son casi equivalentes:

public event Action<EmployeeEventAgs> Leave; 

en contraposición a:

public event EventHandler<EmployeeEventAgs> Leave; 

La diferencia está en la firma del método controlador de eventos. Si se utiliza el primer acercamiento con la acción, usted podría tener:

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

y luego esto:

obj.Leave += LeaveHandler; 

Con el segundo enfoque, la firma de los LeaveHandler tiene que ser diferente:

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

es muy importante a notar º en ambos casos, la palabra clave event está presente. Un evento declarado explícitamente como tal a través de la palabra clave event ya no es un campo de la clase. En cambio, se convierte en una propiedad de evento . Las propiedades del evento son similares a las propiedades normales, excepto que no tienen accesos get o set. El compilador les permite ser utilizados solo en el lado izquierdo de las asignaciones += y -= (agregando o eliminando un manejador de eventos). No hay forma de sobrescribir los controladores de eventos ya asignados, o invocar el evento fuera de la clase que declara.

Si la palabra clave caso faltaba en ambos ejemplos, se puede hacer las siguientes operaciones sin error o advertencia:

obj.Leave = LeaveHandler; 

que borrar cualquier gestores registrados y reemplazarlos withe la LeaveHandler.

Además, también se puede realizar esta llamada:

obj.Leave(new EmployeeEventAgs()); 

Los dos ejemplos anteriores se consideran una anti-patrón, si tiene la intención de crear un evento. Un evento debe invocarse solo por el objeto propietario y no debe permitir imposible de rastrear eliminación de suscriptores. La palabra clave event es la construcción programática de .NET que lo ayuda a seguir con el uso correcto de los eventos.

Teniendo todo lo anterior en mente, creo que muchas personas se adhieren al enfoque EventHandler porque es más improbable que usen un EventHandler sin la palabra clave event. Las acciones tienen un alcance más amplio de uso, no se ven tan naturalmente cuando se usan como eventos. Esta última es, por supuesto, una opinión personal, ya que el enfoque del controlador de eventos probablemente se haya vuelto demasiado rígido en mis prácticas de codificación. Aún así, si las acciones se usan correctamente, no es un crimen usarlas para eventos.

+1

+1 para la explicación detallada. – Joel

Cuestiones relacionadas