2011-07-26 37 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,它引用了父類的信息。

您可以使用反射來找到在編譯器生成的DisplayClass(在Target值)命名<>4__this場,並得到其值設置爲查找創建了委託的類的實例。

但是,不這樣做
這依賴於C#編譯器的內部行爲,該行爲可能隨時發生變化。

此外,閉包類中包含的字段取決於匿名方法的位置以及它引用的成員。如果匿名方法不使用類實例,則它可能根本沒有this字段。

+0

好吧,我想我必須忍受這樣一個事實,即它不可能在這裏使用匿名方法。有沒有辦法找出委託是否是匿名方法而不使用反射?當有人使用匿名方法進行訂閱時,這將有助於添加日誌條目。 – leozilla

+1

檢查'Target'是否是'[CompilerGenerated]'。 – SLaks