¿El remitente de un evento debe ser siempre un objeto genérico?

10

Al programar eventos en C #, se recomienda crear un delegado en forma de:

delegate XEventHandler(object sender, XEventArgs e);

Mi pregunta es sobre el primer argumento del delegado, object sender. ¿Siempre tiene que ser un genérico object? Tener un remitente de tipo objectsiempre da como resultado un código similar a este.

val = ((ConcreteType)sender).Property;

o, incluso más detallado,

ConcreteType obj = sender as ConcreteType
if (obj != null) { ... }

Un argumento contra los remitentes fuertemente tipados es que otros objetos pueden reenviar el evento sin preocuparse por el tipo. Si bien esto puede tener sentido en entornos de GUI, no estoy seguro de si podría beneficiarse fuera de una GUI.

¿Qué sucede si la clase del remitente siempre se conoce (al menos como una clase abstracta)? Por ejemplo, si estoy implementando un ListChangedevento en una Listclase abstracta , y si otras clases lo van a heredar (por ejemplo LinkedList, ArrayList), ¿está bien definir mi delegado con un remitente de tipo List?

delegate ListChangedEventHander(List sender, ListChangedEventArgs e);

O, ¿habría una desventaja de cambiar el convencional object sendera un tipo más específico?

sampathsris
fuente

Respuestas:

10

En este punto, es principalmente una convención (bastante fuerte). Es decir, será extraño si escribe una biblioteca que no sigue esa convención.

Las pautas de diseño de eventos dicen:

DO uso objectcomo el tipo del primer parámetro del controlador de eventos, y lo llaman sender.

Sin embargo, puede observar que la guía actual dice que no debe definir su propio delegado personalizado para eventos, sino utilizarlo EventHandler<T>, si puede.

En cuanto al diseño, supongo que también promueve la reutilización de los controladores de eventos, incluso en contextos no previstos originalmente por el diseñador original del evento.

jhominal
fuente
2
Ughhh ... solo porque Microsoft decidió hacer que sus pautas sean lo suficientemente genéricas como para ser aplicables a todos, no significa que sea una buena idea que todos los demás sigan sus pautas. Es muy probable que "todos los demás" no escriban código para ser utilizado por millones de otros desarrolladores. Me estremecí con aproximadamente 2/3 de las recomendaciones del enlace que proporcionó.
Dunk
A decir verdad, esta "directriz" se parece más o menos a la notación húngara de la API de Windows. Alguien brillante lo comenzó por una muy buena razón y luego todos los demás comenzaron a abusar de él. Cuando hay una guía, es mejor que haya una buena razón detrás de esa guía. Y lo que creo que la razón de esta guía es que el System.Windows.Formsespacio de nombres es el lugar donde los eventos se usan con mayor frecuencia, y tenía sentido suscribirse al Clickevento de Buttono a CheckBox. Por lo tanto, el remitente debe ser genérico. ...
sampathsris
... Pero cuando se trata de otras áreas de funcionalidad más específicas y contenidas, es posible que el remitente no necesite ser una clase genérica. Vea nuevamente mi ejemplo de una jerarquía de clases de Lists.
sampathsris
11
@Dunk: Y ese es el punto. Esta guía proviene de las Pautas de diseño de marcos, que se ocupan principalmente del código que otros consumen . No porque sea la mejor solución, sino porque es la menos sorprendente. Esa es la mejor opción para un marco . Para bibliotecas más pequeñas, si el caso de uso está bien especificado, se aplicará menos orientación. Microsoft lo dice explícitamente al comienzo del libro.
Magus
1
No estoy discutiendo con la respuesta, incluso la voté porque proviene de una fuente confiable. Solo digo que no usaría las pautas. Si se supone que un evento envía datos específicos, simplemente enviaré los datos específicos. Además, la función de evento funciona bien si los usa de la forma en que fueron diseñados.
Dunk
0

La razón de la recomendación es que permite cambios futuros que no necesariamente requieren cambios en el código existente, y especialmente en la interfaz pública.

El mecanismo de evento en sí mismo puede usarse para eventos de estilo "VB6", pero tendrá que cambiar todos los consumidores existentes si alguna vez necesita cambiar la firma (o peor: crear nuevas versiones de los mismos eventos). Con el enfoque recomendado, siempre que los elementos más nuevos hereden de los existentes, puede actualizar la firma sin corregir el código existente.

Mark Hurd
fuente