me encontré con una situación en la que tenía que hacer frente a una Delegate
internamente pero quería una limitación genérica. Específicamente, quería agregar un controlador de eventos utilizando la reflexión, pero quería usar un argumento genérico para el delegado. El código siguiente no funciona, ya que "Handler" es una variable de tipo, y el compilador no desechará Handler
-Delegate
:
public void AddHandler<Handler>(Control c, string eventName, Handler d) {
c.GetType().GetEvent(eventName).AddEventHandler(c, (Delegate) d);
}
Sin embargo, puede pasar una función que hace la conversión para usted. convert
toma un argumento y devuelve un Handler
Delegate
:
public void AddHandler<Handler>(Control c, string eventName,
Func<Delegate, Handler> convert, Handler d) {
c.GetType().GetEvent(eventName).AddEventHandler(c, convert(d));
}
Ahora el compilador es feliz. Llamar al método es fácil. Por ejemplo, adjuntando al evento KeyPress
en un control de Windows Forms:
AddHandler<KeyEventHandler>(someControl,
"KeyPress",
(h) => (KeyEventHandler) h,
SomeControl_KeyPress);
donde SomeControl_KeyPress
es el destino del evento. La clave es el convertidor lambda: no funciona, pero convence al compilador de que le otorgó un delegado válido.
(Begin 280Z28) @Justin: ¿Por qué no utilizar esto?
public void AddHandler<Handler>(Control c, string eventName, Handler d) {
c.GetType().GetEvent(eventName).AddEventHandler(c, d as Delegate);
}
(Fin 280Z28)
+1 por: 1) usando el constructor estático y 2) incluyendo un mensaje detallado debido a condiciones de depuración extrañas que rodean la inicialización de tipo. –
@MarcGravell: No arrojar una excepción en un inicializador estático viola 'CA1065: no levantar excepciones en ubicaciones inesperadas' ... siempre asumí que debes usar una regla de análisis de código personalizado para encontrar usos no válidos de tu clase que normalmente no están disponibles en tiempo de ejecución. –