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

匿名メソッドを含むインスタンスを取得することは可能ですか?または、問題を解決するために完全に異なるアプローチを使用する必要がありますか?

4

1 に答える 1

4

あなたは(おそらく)anonymousメソッドによって使用される変数を含むコンパイラー生成のクロージャークラスを見ています。
このクラスには、親クラスからの情報を参照する特別な名前のフィールドがあります。

リフレクションを使用して、コンパイラによって生成されたDisplayClassTarget値)という名前のフィールドを検索し<>4__this、その値を取得して、デリゲートを作成したクラスのインスタンスを検索できます。

ただし、これは行わないでください。
これは、いつでも変更される可能性のあるC#コンパイラの内部動作に依存しています。

また、クロージャクラスに含まれるフィールドは、anonymousメソッドがどこにあり、どのメンバーを参照しているかによって異なります。匿名メソッドがクラスインスタンスを使用しない場合、thisフィールドがまったくない可能性があります。

于 2011-07-26T19:00:07.617 に答える