2011-07-26 2 views
1

다음 메서드는 파생 클래스가 이벤트에서 누가 알림을 받아야 하는지를 지정할 수 있도록하는 기본 클래스의 일부입니다.익명 메서드의 대상 얻기

protected void RaiseEvent<TEventArgs>(EventHandler<TEventArgs> updateEvent, TEventArgs eventArgs, UpdateReceivers updateReceivers) 
    where TEventArgs : EventArgs 
    { 
    EventHandler<TEventArgs> handler = updateEvent; 
    if (handler != null) 
    { 
     if (updateReceivers.ToAllSubscribers) 
     { 
      handler(this, eventArgs); 
     } 
     else 
     { 
      NotifySpecifiedReceiver(handler, eventArgs, updateReceivers.Receiver); 
     } 
    } 
    } 

    private void NotifySpecifiedReceiver<TEventArgs>(EventHandler<TEventArgs> handler, TEventArgs eventArgs, object updateReceiver) 
    where TEventArgs : EventArgs 
    { 
    foreach (Delegate @delegate in handler.GetInvocationList()) 
    { 
     // is the delegates target our receiver? 
     // but this doesnt work for anonymous methods :(
     if (@delegate.Target == updateReceiver) 
     { 
      try 
      { 
       @delegate.DynamicInvoke(this, eventArgs); 
      } 
      catch (Exception ex) 
      { 
      } 
     } 
    } 
    } 

만 특정 수신자에게 알리려면 방법은 다음과 같이 사용됩니다

event EventHandler<SomethingChangedEventArgs> SomethingChanged; 

RaiseEvent(SomethingChanged, args, UpdateReceivers.Single(receiver)); 

에만 수신기에 "가리키는"대의원을 올릴 것이다 (수신기 물론 가입해야합니다) .

여기 내 문제는 익명 메서드를 사용하여 SomethingChanged 이벤트를 구독 할 때 내가이 이벤트를 사용하여 구독 한 개체에 알릴 때 발생합니다.

class EventConsumer 
{ 
    private EventSource _eventSource; 

    private void SubscribeEvents() 
    { 
     // ReactOnEvent() will not be called because the check [@delegate.Target == updateReceiver] doesnt work for anonymous methods 
     _eventSource.MyStateChanged += (sender, e) => ReactOnEvent(); 

     _eventSource.PublishCurrentState(this); 
    } 
} 

class EventSource 
{ 
    // multiple objects are subscribed to this event 
    event EventHandler<MyStateChangedEventArgs> MyStateChanged; 

    public void GetCurrentState(object receiver) 
    { 
     // receiver ask for the current state, only raise event for him 
     RaiseEvent(MyStateChanged, args, UpdateReceivers.Single(receiver)); 
    } 
} 

익명 메소드가 포함 된 인스턴스를 가져올 수 있습니까? 또는 내 문제를 해결하기 위해 완전히 다른 접근 방식을 사용해야합니까?

+0

'DynamicInvoke'를 호출하면 안됩니다. – SLaks

+0

대리인을 호출하는 또 다른 방법이 있습니까? – leozilla

+0

'@delegate (this, eventArgs)'형식이 지정되지 않은 델리게이트에만 'DynamicInvoke'가 필요합니다. (리플렉션을 사용하여 메서드를 호출 함) – SLaks

답변

4

아마도 익명 메소드에서 사용되는 변수가 포함 된 compiler-generated closure class이 표시 될 것입니다.
이 클래스는 부모 클래스의 정보를 참조하는 specifically-named fields입니다.

당신은 <>4__this라는 컴파일러가 생성 DisplayClass합니다 (Target 값)의 필드를 찾기 위해 반사를 사용하고 대리자를 생성 한 클래스의 인스턴스를 찾아 그 값을 얻을 수 있습니다.

그러나 .
이것은 언제든지 변경 될 수있는 C# 컴파일러의 내부 동작을 기반으로합니다.

또한 closure 클래스에 포함 된 필드는 익명 메소드의 위치와 참조하는 멤버에 따라 다릅니다. 익명 메서드가 클래스 인스턴스를 사용하지 않으면 필드에 this이 전혀 없을 수 있습니다.

+0

좋아요. 익명의 방법을 사용할 수 없다는 사실을 알고 살아야 할 것 같습니다. 대리인이 리플렉션을 사용하지 않고 익명 메소드인지 확인하는 방법이 있습니까? 누군가가 익명 메소드를 사용하여 등록 할 때 로그 항목을 추가하는 것이 도움이 될 것입니다. – leozilla

+1

'Target '이'[CompilerGenerated]'인지 확인하십시오. – SLaks