2011-03-15 15 views
5

몇 가지 이벤트가있는 클래스를 고려하십시오. 이 이벤트 목록은 점점 커질 것입니다. 일부는 선택 사항입니다. 다른 것들이 필요합니다.런타임 동안 리플렉션을 사용하여 주어진 이벤트가 등록되어 있는지 확인하십시오.

일부 초기 유효성 검사를 간소화하기 위해 이벤트에 필수 속성으로 표시하는 사용자 지정 특성이 있습니다. 예 :

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

지금까지 그렇게 좋았습니다. 모든 이벤트의 유효성을 검사하려면 리플렉션을 사용하여 이벤트 목록을 반복하고 사용자 지정 특성을 가져옵니다. 그러나 이벤트 구독 여부를 결정할 방법이 필요합니다.

반영하지 않고 ServiceStarted.GetInvocationList가 작업을 수행합니다. 그러나 이벤트는이 목록에서 가져와야합니다. var eventList = this.GetType(). GetEvents(). ToList();

이벤트 목록의 특정 이벤트가 리플렉션을 사용하여 구독되어 있는지 확인하는 방법이 있습니까?

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()); 
    } 

많은 감사합니다! :

- - [업데이트] 다음은 아미의 답변에 따라 가능한 솔루션입니다

+3

IMHO, 예를 들어, 이 모든 이벤트가 C 번호 필드와 같은 이벤트의 현재 구현으로 구현된다고 가정하면 (강하게 실망 )과 같은 작업을 수행 할 수 있습니다 , 처음에는 이벤트가 아니라 클래스의 생성자에 대한 대리자 매개 변수가되도록하십시오. –

+0

유효성 검사를 수행하는 것은 무엇이며,이 맥락에서 "필요한 것"은 무엇을 의미합니까? 누구에게 필수인가? –

+0

@ 대니얼 (Daniel), 이것이 제가 처음 접근 한 방법이었습니다. 그러나 많은 사람들을 코드로 보내서이 실험을하게되었습니다. – Bruno

답변

4

여기에는 몇 가지 주요 디자인 문제가 있습니다. 일반적으로 이벤트 구독자가 누구인지 물어볼 방법이 없습니다. 그것은 누군가가이 기능을 원하는 것이 매우 드문,하지만 당신이 정말로 그것을 원한다면, 당신은 클래스가 어떻게 든 예를 들어, 방법 등으로 인터페이스를 구현하여,이 노출 얻어야한다 : 어쨌든

public IEnumerable<Delegate> GetSubscribers(string eventName); 

질문에 답하기 위해 은 리플렉션을 사용하지만 구독자가 어떻게 유지되고 있는지 정확하게 알고있는 경우에만 가능합니다. 이벤트에 가입하는 것이 필요한 경우

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

디자인 결함에 대한 귀하의 요점을 보았습니다. :/여전히 당신의 해결책은 좋은 방향으로 나를 인도합니다! GetField (-eventname-)와 바인딩 플래그가 문제를 해결했습니다! – Bruno

관련 문제