2011-03-15 11 views
5

Considera una clase que tiene algunos eventos. Esta lista de eventos va a crecer. Algunos son opcionales Otros son obligatoriosComprueba si un evento dado está suscrito, durante el tiempo de ejecución, usando la reflexión

Para simplificar alguna validación inicial, tengo un atributo personalizado que marca un evento como uno requerido. Por ejemplo:

[RequiredEventSubscription("This event is required!")] 
    public event EventHandler ServiceStarted; 

Hasta ahora todo bien. Para validar todos los eventos, utilizando la reflexión iteraré la lista de eventos y tomaré los atributos personalizados. Pero necesito una forma de determinar si el evento está suscrito o no.

Sin reflexión, ServiceStarted.GetInvocationList hace el trabajo. Pero el evento debe provenir de esta lista: var eventList = this.GetType(). GetEvents(). ToList();

¿Hay alguna forma de comprobar si un evento determinado, de una lista de eventos, se suscribe utilizando la reflexión?

- [Actualización] - Aquí hay una posible solución basada en la respuesta de Ami:

private void CheckIfRequiredEventsAreSubscribed() 
    { 
     var eventList = GetType().GetEvents().ToList().Where(e => Attribute.IsDefined(e, typeof(RequiredEventSubscription))); 

     StringBuilder exceptionMessage = new StringBuilder(); 
     StringBuilder warnMessage = new StringBuilder(); 

     foreach (var evt in eventList) 
     { 
      RequiredEventSubscription reqAttr = (RequiredEventSubscription) evt.GetCustomAttributes(typeof(RequiredEventSubscription), true).First(); 
      var evtDelegate = this.GetType().GetField(evt.Name, BindingFlags.Instance | BindingFlags.NonPublic); 
      if (evtDelegate.GetValue(this) == null) 
      { 
       warnMessage.AppendLine(reqAttr.warnMess); 
       if (reqAttr.throwException) exceptionMessage.AppendLine(reqAttr.warnMess); 
      } 
     } 
     if (warnMessage.Length > 0) 
      Console.WriteLine(warnMessage); 
     if (exceptionMessage.Length > 0) 
      throw new RequiredEventSubscriptionException(exceptionMessage.ToString()); 
    } 

Muchas gracias !!

+3

en mi humilde opinión, si la suscripción de un evento se requiere , no lo convierta en un evento en primer lugar, sino en un parámetro de delegado para el constructor de su clase. –

+0

¿Qué significa validar y qué significa "requerido" en este contexto? Requerido para quién/qué? –

+0

@ Daniel, ese fue mi primer enfoque, pero enviar tantos delegados a lo largo del código me llevó a este experimento. – Bruno

Respuesta

4

Aquí hay algunos problemas importantes de diseño. En general, no hay forma de preguntarle a un objeto quiénes son los suscriptores de sus eventos. Es muy raro que alguien quiera esta funcionalidad, pero si realmente lo desea, usted debe recibir clases para exponer alguna manera esto, por ejemplo, mediante la implementación de una interfaz con un método como:

public IEnumerable<Delegate> GetSubscribers(string eventName); 

todos modos , para responder a la pregunta, puede utilizar la reflexión, pero solo si sabe exactamente cómo se mantienen los suscriptores. Por ejemplo, asumiendo que todo eventos se implementan con la actual aplicación de C# eventos de campo como, usted puede hacer algo como (fuertemente desanimado):

object o = ... 

var unsubscribedEvents = 
    from e in o.GetType().GetEvents() 
    where Attribute.IsDefined(e, typeof(RequiredEventSubscriptionAttribute)) 
    let field = o.GetType() 
       .GetField(e.Name, BindingFlags.NonPublic | BindingFlags.Instance) 
       .GetValue(o) 
    where field == null 
    select field; 

var isValid = !unsubscribedEvents.Any(); 
+0

Veo su punto sobre el error de diseño:/¡Todavía su solución me lleva en una buena dirección! GetField (-eventname-) y las banderas vinculantes resolvieron el problema. – Bruno

Cuestiones relacionadas