2009-04-30 9 views
16

Considere este escenario. Tengo un objeto, vamos a llamarlo ... Foo. Foo plantea un evento simple llamado "Cargado". Como parte de la información para el evento, los consumidores necesitarán saber qué objeto Foo planteó el evento. Nuestro equipo ha adoptado el siguiente patrón.C# simple Recaudación de eventos: usar "remitente" frente a EventArgs personalizados

1) Cree una clase nueva que herede de EventArgs; por ejemplo, FooEventArgs: System.EventArgs.

2) Agregue una propiedad de tipo Foo a FooEventArgs, que se establece al pasarla a través del constructor.

3) Declarar el evento utilizando la versión genérica del manejador de sucesos, por lo

public event EventHandler<FooEventArgs> Loaded; 

4) Elevar el caso de la clase Foo con la siguiente firma:

Loaded(this, new FooEventArgs(this)); 

Básicamente lo que hace es hace que el "emisor" sea el objeto foo, pero también pone la referencia del objeto foo en el argumento del evento como una propiedad fuertemente tipada.

Una de las ventajas de hacer esto es que nadie tiene que molestarse en enviar "remitente" cuando manejan el evento, lo que reduce el acoplamiento entre el consumidor del evento y el evento. Otra "ventaja" es que si el tipo del evento eventual tiene que cambiar, y por lo tanto la propiedad fuertemente tipada (que afortunadamente nunca ocurre), entonces en lugar de simplemente tener un código que comience a fallar en el elenco cuando sea nulo, la API realmente se rompe, por lo que se puede arreglar en tiempo de compilación.

Para mí, este patrón parece que podría ser excesivo. ¿Deberían confiar más en el parámetro "remitente" y abandonar los argumentos de eventos personalizados? Mi equipo argumenta que nadie realmente usa el parámetro del remitente. ¿Cuál es la mejor práctica para pasar una referencia al objeto de suceso?

EDIT: Gran retroalimentación hasta ahora, voy a dejar esto abierto por otro día más o menos antes de aceptar uno.

+4

Por otro enfoque a esto, es posible que desee echar un vistazo a "Firma Evento en .NET - ¿Cómo usar un "emisor" fuerte? aquí: http://stackoverflow.com/questions/1046016/event-signature-in-net-using-a-strong-typed-sender –

Respuesta

9

El patrón común es usar remitente y no agregar el remitente por separado a EventArgs. El EventArgs personalizado se utiliza para otro estado como un nodo de árbol para un evento de árbol, un booleano (configurable) para un evento cancelable, etc.

Usamos el patrón común ya que también lo usan las clases BCL y hacemos un diferencia para "eventos hechos a sí mismos" es potencialmente confuso. Además, tenemos un patrón de suscriptor de editor de IoC global, pero este solo funciona con la firma de delegado de EventHandler normal, ya que los tipos no se conocen de antemano. En este caso, es necesario un cast (por ejemplo, un EventArgs personalizado) de todos modos, así que podríamos enviar el remitente.

2

Yo diría que la convención tiene mucho que ofrecer. Hay menos para mantener en el largo plazo - esp. si recibe gente nueva.

2

Supongo que es una cuestión de preferencia hasta cierto punto, pero en mi caso cuando leí el consumers will need to know which foo object raised the event. inmediatamente pensé que puede obtener el objeto que generó el evento desde el argumento del remitente, entonces ¿cuál es el ¿problema?

Su equipo tiene algunos puntos válidos (al tener una propiedad fuertemente tipada), pero yo diría que trabajar con las directrices marco en lugar de inventar la suya sería una mejor decisión a largo plazo.

3

No creo que esto sea exagerado. Estoy de acuerdo con las ventajas que indica por tener una clase FooEventArgs separada. Otra ventaja de hacerlo de esa manera es que si necesita agregar más información al evento en el futuro, puede agregar más propiedades a FooEventArgs y no necesita cambiar el delegado.

+0

"Creo que también es una práctica recomendada de Microsoft hacerlo de esta manera" - do usted tiene alguna referencia a esto? – Lucero

+0

Definitivamente es una práctica recomendada para agregar información adicional a los eventos mediante el uso de una subclase de EventArgs. Ver: http://msdn.microsoft.com/en-us/library/aa645739(VS.71).aspx o http://www.codeproject.com/KB/cs/event_fundamentals.aspx. En cuanto a agregar el remitente a eventargs ... es por eso que estoy pidiendo: p – womp

+0

Siempre y cuando los FooEventArgs hereden de EventArgs, un delegado con la firma de (object, EventArgs) puede manejar el evento. Entonces puede usar EventArgs ahora y luego cambiarlo a FooEventArgs si necesita parámetros. –

3

Yo diría que quita la subclase de EventArgs y usa la propiedad del remitente para identificar al remitente del evento. Creo que el argumento para seguir la convención tiene sus méritos, pero el parámetro en EventArgs no es necesario. Yo personalmente lo soltaría y solo usaría la propiedad del remitente.

Si quieres pasarlo como un tipo fuerte, usted podría también acaba de crear un delegado costumbre de utilizar para su evento ...

public delegate void LoadedHandler(FooEventArgs args); 

de esa manera se podría tenerlo como un tipo fuerte .. La reutilización de delegados es excelente, pero si no se ajustan a lo que intentas hacer, no debes sentirte obligado a utilizar únicamente los integrados.

2

Por lo que se refiere a las prácticas recomendadas, he visto un nulo como remitente en Windows Workflow Foundation bastante. Idealmente, sus suscriptores deberían ignorar el objeto que genera eventos.

Si necesita pasar el objeto llamador como un todo a los controladores, debe colocarlo en un objeto derivado de EventArgs. Alternativamente, prefiero pasar explícitamente las partes del estado del llamador del evento/llamante en lugar de todo el asunto.

Bueno, a veces es más fácil pensar dotNET 1.1, donde

Control.Invoke() 

se utiliza con tanta frecuencia como

int i; 
+2

¿Qué te hace decir: "Idealmente, tus suscriptores deberían ignorar el objeto que genera eventos"? Eso parece contrario a todos los casos de uso de eventos que se me ocurren. –

+0

En un gran diseño, los evens deben poder cruzar los límites del dominio de la aplicación, los límites entre el cliente y el servidor, y deben funcionar bien a través de la comunicación interestelar :) Esto significa que el remitente debe empaquetar todas las cosas relacionadas con este evento de manera serializable y suministrarlos a través de un hijo de EventArgs. No conozco ningún caso en el que el argumento del remitente del objeto sea un requisito absoluto. – GregC

Cuestiones relacionadas