c# - org - Los eventos no son campos, no lo entiendo
mapwindows 5 (5)
En C # en profundidad (un excelente libro hasta el momento), Skeet explica que los eventos no son campos . Leí esta sección muchas veces y no entiendo por qué la distinción hace alguna diferencia.
Soy uno de esos desarrolladores que confunden eventos y delega instancias. En mi opinión, son lo mismo. ¿No son ambas una forma de indirección? Podemos multidifundir ambos. Un evento se configura como un campo como taquigrafía ... seguro. Pero, estamos agregando o eliminando controladores. Apilarlos para que se llamen cuando se desate el evento. ¿No hacemos lo mismo con los delegados, los apilamos y llamamos a invocar?
Consideremos las dos formas de declarar eventos.
O declaras un evento usando un método explícito de add
/ remove
o declaras un evento sin dichos métodos.
En otras palabras, declaras el evento así:
public event EventHandlerType EventName
{
add
{
// some code here
}
remove
{
// some code here
}
}
o lo declaras así:
public event EventHandlerType EventName;
La cuestión es que, en cierto modo, son lo mismo y, en otros aspectos, son completamente diferentes.
Desde la perspectiva del código externo, es decir ... código fuera de la clase que publica el evento, son exactamente lo mismo. Para suscribirse a un evento, llame a un método. Para darse de baja, llame a un método diferente.
La diferencia es que en el segundo código de ejemplo anterior, el compilador proporcionará esos métodos, sin embargo, así es como será. Para suscribirse al evento, llame a un método.
La sintaxis para hacerlo, en C #, sin embargo, es la misma, usted puede hacer lo siguiente:
objectInstance.EventName += ...;
o:
objectInstance.EventName -= ...;
Entonces, desde la "perspectiva externa", las dos formas no son diferentes en absoluto.
Sin embargo, dentro de la clase, hay una diferencia.
Si intenta acceder al identificador de EventName
dentro de la clase, en realidad se está refiriendo al field
que respalda la propiedad, pero solo si usa la sintaxis que no declara explícitamente un método add
/ remove
.
Un patrón típico es como esto:
public event EventHandlerType EventName;
protected void OnEventName()
{
var evt = EventName;
if (evt != null)
evt(this, EventArgs.Empty);
}
En este caso, cuando se refiere a EventName
, en realidad se está refiriendo al campo que contiene el delegado de tipo EventHandlerType
.
Sin embargo, si ha declarado explícitamente los métodos para add
/ remove
, consultar el identificador de EventName
dentro de la clase será como estar fuera de la clase, ya que el compilador no puede garantizar que conoce el campo o cualquier otro mecanismo en el que almacenar la suscripción.
Las otras respuestas son básicamente correctas, pero aquí hay otra manera de verlo:
Soy uno de esos desarrolladores que confunden eventos y delega instancias. En mi opinión, son lo mismo.
Me viene a la mente un viejo refrán sobre no ver el bosque por los árboles. La distinción que hago es que los eventos están en un "nivel semántico" más alto que un campo de instancia de delegado. Un evento le dice al consumidor del tipo "Hola, soy del tipo que le gusta contar cuando sucede algo". El tipo fuentes un evento; eso es parte de su contrato público.
Cómo, como detalle de la implementación, esa clase elige hacer un seguimiento de quién está interesado en escuchar ese evento, y qué y cuándo decirle a los suscriptores que el evento está sucediendo, es asunto de la clase. Suele hacerlo con un delegado de multidifusión, pero eso es un detalle de implementación. Es un detalle de implementación tan común que es razonable confundir a los dos, pero realmente tenemos dos cosas diferentes: una superficie pública y un detalle de implementación privada.
De forma similar, las propiedades describen la semántica de un objeto: un cliente tiene un nombre, por lo que una clase de Cliente tiene una propiedad de Nombre. Podría decir que "su nombre" es propiedad de un cliente, pero nunca diría que "su nombre" es un campo de un cliente; eso es un detalle de implementación de una clase particular, no un hecho sobre la semántica empresarial. Que una propiedad se implementa típicamente como un campo es un detalle privado de la mecánica de clase.
Las propiedades tampoco son campos, aunque se sienten como ellos. En realidad, son un par de métodos (getter y setter) con sintaxis especial.
Los eventos son, de manera similar, un par de métodos (suscribirse y cancelar suscripción) con sintaxis especial.
En ambos casos, generalmente tiene un "campo de respaldo" privado dentro de su clase, que contiene el valor manipulado por los métodos getter / setter / subscribe / unsubscribe. Y hay una sintaxis implementada automáticamente para las propiedades y los eventos donde el compilador genera el campo de respaldo y los métodos de acceso para usted.
El propósito también es el mismo: las propiedades proporcionan acceso restringido a un campo, donde se ejecuta cierta lógica de validación antes de almacenar un nuevo valor. Y un evento proporciona acceso restringido a un campo de delegado, donde los consumidores solo pueden suscribirse o cancelar su suscripción, no leer la lista de suscriptores, ni reemplazar toda la lista a la vez.
Puedo agregar a las respuestas anteriores que los delegados se pueden declarar dentro de un ámbito de espacio de nombres (fuera de una clase) y los eventos solo se pueden declarar dentro de una clase. ¡Esto se debe a que el delegado es una clase!
Otra distinción es que, para los eventos, la clase contenedora es la única que puede dispararla. Puede suscribirse / anular su suscripción a través de la clase contenedora, pero no puede iniciarla (a diferencia de los delegados). Así que tal vez ahora pueda entender por qué la convención es envolverlo dentro de un protected virtual OnSomething(object sender, EventArgs e)
. Es para que los descendientes puedan anular la implementación del disparo.
Un evento es un acceso para un delegado. Al igual que una propiedad es un descriptor de acceso para un campo. Con la misma utilidad exacta, evita que el código se meta con el objeto delegado. Al igual que una propiedad tiene un acceso de obtención y configuración, un evento tiene el acceso de acceso de inserción y eliminación.
Se comporta de una manera algo diferente de una propiedad, si no escribe el complemento y elimina los accesos usted mismo, entonces el compilador los genera automáticamente. Incluyendo un campo de respaldo privado que almacena el objeto delegado. Similar a una propiedad automática.
No haces esto a menudo, pero ciertamente no es inusual. El framework .NET lo hace bastante comúnmente, por ejemplo los eventos de los controles Winforms se almacenan en una EventHandlerList y los accessors add / remove manipulan esa lista a través de sus métodos AddHandler () y RemoveHandler (). Con la ventaja de que todos los eventos (hay muchos) requieren un solo campo en la clase.