Search code examples
c#.netsystem.componentmodel

Is it possible to check whether an Event is null if i only got the EventDescriptor?


My constructor parses its instance for events with a certain attribute:

_EventAttributes = from EventDescriptor a in TypeDescriptor.GetEvents(this)
            let attribute = a.Attributes[typeof(MyAttribute)] as MyAttribute
            where attribute != null
            select new EventAttributeTuple { Event = a, Attribute = attribute };

Later in the code i want to check whether the corresponding event is null (nobody is interested in the event) to decide whether or not i have to write it in my XML output:

//write events
foreach (var attr in _EventAttributes)
{
    if (check corresponding attr.Event object is null)
    {
        writer.WriteAttributeString(attr.Attribute.Name, GetRPCAdress(attr.Event.Name));
    }
}

EDIT:

Getting the EventInfo is also quite easy:

var evtInfo = this.GetType().GetEvent(attr.Event.Name);

But still, i don't know how to check whether the event has subscribers or not.

EDIT2:

After looking at the generated code with dotPeek, I think there is no chance to access any field here:

    //original code
    [MyAttribute("onclick")]
    public event EventHandler<MouseArg> Click;

    //generated code
    [MyAttribute("onclick")]
    public event EventHandler<MouseArg> Click
    {
      add
      {
        EventHandler<MouseArg> eventHandler = this.Click;
        EventHandler<MouseArg> comparand;
        do
        {
          comparand = eventHandler;
          eventHandler = Interlocked.CompareExchange<EventHandler<MouseArg>>(ref this.Click, comparand + value, comparand);
        }
        while (eventHandler != comparand);
      }
      remove
      {
        EventHandler<MouseArg> eventHandler = this.Click;
        EventHandler<MouseArg> comparand;
        do
        {
          comparand = eventHandler;
          eventHandler = Interlocked.CompareExchange<EventHandler<MouseArg>>(ref this.Click, comparand - value, comparand);
        }
        while (eventHandler != comparand);
      }
    }

There may be a chance, if i handle all of the event add/remove operations myself, but that seems very tedious. Anyone has a better idea?

EDIT3:

I got it, i was using this.GetType() which does not give me the declaring type but was a subclass of the class which declares the event, hence i was not able to retrieve the field.

It now works like this:

var evtValue = attr.Event.ComponentType.GetField(attr.Event.Name, 
               BindingFlags.Instance | BindingFlags.NonPublic).GetValue(this);

Solution

  • Sorry, this is impossible in general case, for instance:

      class CounterExample {
        public event EventHandler MyEvent {
          add {
            // You can't control me here: whether I truly add an event or not 
            // and even if I always add the event - where I store it
          }
          remove {
            // You can't control me here: whether I truly remove an event or not
            // and even if I always remove the event - from where I delete it
          }
        }
      }
    

    But in many cases you can do a hack (be careful though):

      class SimpleCase { 
        // Usual event realization (default add and remove accessors)
        public event EventHandler MyEvent; 
      }
    
      ...
      SimpleCase cs = new SimpleCase();
      cs.MyEvent += ...
      ...
    
      // Since MyEvent has default accessors, lets check the default storage: 
      FieldInfo fi = cs.GetType().GetField("MyEvent", BindingFlags.NonPublic | BindingFlags.Instance);
      Boolean myEventAssigned = !Object.ReferenceEquals(fi.GetValue(cs), null);