Me encontré con una situación en la que necesitaba lidiar con una Delegate
restricción interna pero quería una restricción genérica. Específicamente, quería agregar un controlador de eventos usando la reflexión, pero quería usar un argumento genérico para el delegado. El siguiente código NO funciona, ya que "Handler" es una variable de tipo y el compilador no se convierte Handler
en 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 realice la conversión por usted. convert
toma un Handler
argumento y devuelve un 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 está contento. Llamar al método es fácil. Por ejemplo, adjuntar al KeyPress
evento en un control de Windows Forms:
AddHandler<KeyEventHandler>(someControl,
"KeyPress",
(h) => (KeyEventHandler) h,
SomeControl_KeyPress);
¿Dónde SomeControl_KeyPress
está el objetivo del evento? La clave es el convertidor lambda: no funciona, pero convence al compilador de que le dio un delegado válido.
(Comienza 280Z28) @Justin: ¿Por qué no usar esto?
public void AddHandler<Handler>(Control c, string eventName, Handler d) {
c.GetType().GetEvent(eventName).AddEventHandler(c, d as Delegate);
}
(Fin 280Z28)
CA1065: Do not raise exceptions in unexpected locations
... Siempre asumí que debería usar una regla de análisis de código personalizado para encontrar usos no válidos de su clase que normalmente no están disponibles en tiempo de ejecución.where T : Delegate
, (y alguien publicó una nueva respuesta sobre eso a continuación).