Dynamically Attaching Delegates Revisited

I previously wrote a post showing how, given a service with many events, I was able to dynamically attach an event handler based on certain conditions. This was done directly within my constructor for the object. Today I was looking at that same code and I couldn’t shake the feeling it looked odd having such a big segment of code in the constructor. I thought about moving it out to its own function and realized how many parameters I would have to send over. I decided to instead write an extension method.

At first I targeted the base class for my communication object but that would be tying the code to Silverlight. Right now that’s the only place I need it but I’ve done some code sharing between my Silverlight project and my WCF classes and I can easily see wanting to use this code over and over again. That said, here’s what I came up with:

public static class EventHandlerAttachmentExtensions
{
   public static void RegisterListenerForEvents(this object objectWithEvents,
                                 EventHandler genericHandler, Predicate eventCheck)
   {
      if (null == genericHandler)
         throw new ArgumentNullException("genericHandler");
      if (null == eventCheck)
         throw new ArgumentNullException("eventCheck");

      EventInfo[] events = objectWithEvents.GetType().GetEvents();
      foreach(EventInfo evt in events)
      {
         if (eventCheck(evt))
         {
            evt.AddHandler(objectWithEvents, Delegate.CreateDelegate(
                  evt.EventHandlerType, genericHandler.Target, genericHandler.Method));
         }
      }
   }
}

This extension method can be exposed on any object. This is because any object can define events. The upside is that we can use this on any object. The downside is this method extension will show up in every object in your project. You could change the base class to something more specific but I like the flexibility.

The delegate you pass in for the genericHandler must be public or you’ll get a MemberAccessException. If you don’t want your event handler public, then move the code into the class that defines the delegate and call it like a regular function rather than an extension.

The predicate for eventCheck is just a set of instructions the event must pass in order for the delegate to be attached. This gives you the ability to discriminate a little bit and ensure you only attach to events you care about.

If you want to use the ParallelForEach again, it works quite well. Just know that if for some reason the AddEventHandler call throws an exception you won’t know and this could lead to unexpected behavior. For generic code where I don’t have tight control over both sides of the equation, I prefer not to hide exceptions and let them bubble up. In .NET 4 with the AggregateException class maybe it would be alright to run in parallel and simply gather up the exceptions to be thrown at the end but I’m constrained to .NET 3.5 and this is the way I’ve chosen.

In my Silverlight project, where I once had all the code and logic embedded in my constructor, I now have:

public class ConnectionServer
{
   ...
   ...

   public void CheckForInvalidCondition(object sender, EventArgs e)
   {
      ... //Same as before
   }

   ConnectionService()
   {
      ...
      ...

      WcfClient.RegisterListenerFroEvents(
            CheckForInvalidCondition,
            evt => evt.EventHandlerType.IsGenericType &&
            null != evt.EventHandlerType.GetGenericArguments()[0].GetProperty("Result")
         );
   }
}

Take care,
-Erik

Advertisements

2 responses to “Dynamically Attaching Delegates Revisited

  1. Erik, Have you looked at Reactive Extensions for .NET. I haven’t researched it much, but it seems to be in the same topic as this blog post.

    http://msdn.microsoft.com/en-us/devlabs/ee794896.aspx

    • Hi Steve,

      I’ve looked at Rx from a conceptual point of view and I’m excited to use it but I’ve been unable to convince my team to try it out on our current project. Most of my posts stem from active work I’m doing while the information is fresh but I am trying to come up with a non-trivial, useful example of SharePoint, WCF, Silverlight (with Rx). Maybe until I can find the time to flesh that out I can do smaller scoped Rx stuff.

      Thanks for the great idea!

      -Erik

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s