c# events extension-methods

c# - ¿Llamar mal a un método de extensión con una referencia "nula"(es decir, un evento sin suscriptores)?



events extension-methods (8)

¿Malvado o no malvado?

public static void Raise(this EventHandler handler, object sender, EventArgs args) { if (handler != null) { handler(sender, args); } } // Usage: MyButtonClicked.Raise(this, EventArgs.Empty); // This works too! Evil? EventHandler handler = null; handler.Raise(this, EVentArgs.Empty);

Tenga en cuenta que debido a la naturaleza de los métodos de extensión, MyButtonClicked.Raise no lanzará una NullReferenceException si MyButtonClicked es nulo. (Por ejemplo, no hay oyentes en el evento MyButtonClicked).

¿Malvado o no?


¿Por qué sería malo?

Su propósito es claro: aumenta el evento MyButtonClicked.

Agrega una sobrecarga de llamada de función, pero en .NET se optimizará o muy rápido de todos modos.

Es un poco trivial, pero soluciona mi mayor queja con C #.

En general, creo que es una idea fantástica, y probablemente la robe.


Aunque no lo describiría como malvado , aún tiene una implicación negativa, ya que agrega una sobrecarga innecesaria:

Cuando llamas

myEvent.Raise(this, new EventArgs());

el objeto EventArgs se inicializa en todas las situaciones, incluso si nadie se suscribió a myEvent.

Cuando usas

if (myEvent!= null) { myEvent(this, new EventArgs()); }

EventArgs solo se inicializa si alguien se suscribió a myEvent.


Lanzar una excepción cuando no hay controladores en realidad no es lo más preferible. Si no tiene controladores, es mejor estar vacío que nulo.


No diría que es malo, pero estoy interesado en cómo su método de extensión se ajusta al

protected virtual OnSomeEvent(EventArgs e){ }

patrón y cómo maneja la extensibilidad a través de la herencia. ¿Supone que todas las subclases manejarán el evento en lugar de anular un método?


No malvado Deseo que los eventos funcionen de esta manera por defecto. ¿Alguien puede explicar por qué un evento sin suscriptores es nulo?


No te olvides de usar [MethodImpl(MethodImplOptions.NoInlining)] , de lo contrario es posible que no sea seguro para subprocesos.

(Lea eso en algún lugar hace mucho tiempo, lo recordó, buscó en Google y encontró http://blog.quantumbitdesigns.com/tag/events/ )


Siempre puedes declarar tus eventos así (no es que lo recomiende):

public event EventHandler<EventArgs> OnClicked = delegate { };

De esta forma, tienen algo asignado cuando los llamas, por lo que no arrojan una excepción de puntero nulo.

Probablemente pueda deshacerse de la palabra clave de delegado en C # 3.0 ...


Viniendo de un fondo java, esto siempre me ha parecido extraño. Creo que nadie que escuche un evento es perfectamente válido. Especialmente cuando los oyentes se agregan y eliminan dinámicamente.

Para mí, esta parece ser una de las ocurrencias de C # que causa errores cuando las personas no saben / olvidan verificar nulos cada vez.

Ocultar este detalle de implementación parece ser un buen plan ya que no ayuda a la legibilidad a verificar nulos cada vez. Estoy seguro de que los MSFT dirán que hay un aumento en el rendimiento al no producir el evento si nadie está escuchando, pero también está ampliamente compensado por las excepciones / reducción de la puntería del puntero nulo sin sentido en la mayoría de los códigos comerciales.

También agregaría estos dos métodos a la clase:

public static void Raise(this EventHandler handler, object sender) { Raise(handler, sender, EventArgs.Empty); } public static void Raise<TA>(this EventHandler<TA> handler, object sender, TA args) where TA : EventArgs { if (handler != null) { handler(sender, args); } }