Получение цели анонимного метода - PullRequest
1 голос
/ 26 июля 2011

Следующие методы являются частью базового класса, который позволяет производным классам указывать, кого следует уведомить о событии.

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

Возможно ли получить экземпляр, содержащий анонимный метод? или я должен использовать совершенно другой подход для решения моей проблемы?

1 Ответ

4 голосов
/ 26 июля 2011

Вы (предположительно) видите сгенерированный компилятором класс замыкания , который содержит переменные, используемые анонимным методом.
Этот класс имеет поля с особым именем , которые ссылаются на информацию из родительского класса.

Вы можете использовать отражение, чтобы найти поле в сгенерированном компилятором DisplayClass (значение Target) с именем <>4__this и получить его значение, чтобы найти экземпляр класса, создавшего делегат.

Однако, не делайте этого .
Это зависит от внутреннего поведения компилятора C #, которое может измениться в любое время.

Кроме того, поля, содержащиеся в классе замыкания, зависят от того, где находится анонимный метод и на какие члены он ссылается. Если анонимный метод не использует экземпляр класса, он может вообще не иметь поля this.

...