1

The following methods are part of a base class which enables derived classes to specify who should be notified by an event.

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

To notify only a specific receiver, the method is used like this: (the receiver has to be subscribed of course)

event EventHandler<SomethingChangedEventArgs> SomethingChanged;

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

This will only raise the delegates "pointing" to the receiver.

My problem here is when i use a anonymous method to subscribe to the SomethingChanged event its doesnt work when i use this event to notify the object which subscribed to it.

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

Is it possible the get the instance containing a anonymous method? or should i use a complete different approach to solve my problem?

John Saunders
  • 160,644
  • 26
  • 247
  • 397
leozilla
  • 1,296
  • 2
  • 19
  • 29

1 Answers1

4

You're (presumably) seeing the compiler-generated closure class that contains variables used by the anonymous method.
This class has specifically-named fields that reference information from the parent class.

You can use reflection to find a field in the compiler-generated DisplayClass (the Target value) named <>4__this, and get its value to find the instance of the class that created the delegate.

However, don't do this.
This relies on an internal behavior of the C# compiler that may change at any time.

Also, the fields contained by the closure class depend on where the anonymous method is and what members it references. If the anonymous method doesn't use the class instance, it may not have a this field at all.

Community
  • 1
  • 1
SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
  • Ok, i think i will have to live with the fact that its not possible to use anonymous methods here. Is there a way to find out if the delegate is an anonymous method without using reflection? this would be helpfull to add a log entry when someone uses a anonymous method to subscribe. – leozilla Jul 26 '11 at 19:12
  • 1
    Check whether the `Target` is `[CompilerGenerated]`. – SLaks Jul 26 '11 at 19:22