Part III: The OpenNETCF.IoC Framework: Events

Articles in this series
Part I: Inversion of Control and the Compact Framework
Part II: The OpenNETCF.IoC Framework: Items and Services
Part III: The OpenNETCF.IoC Framework: Events (this article)
Part IV: The OpenNETCF.IoC Framework: Performance (TBD)

Downloads
Code and Sample available through CodePlex.


In the Part II of this series we looked at how the OpenNETCF.IoC framework provides dependency injection for the lists of Items and Services and if you look at the sample application that ships with the framework you’ll see that the application creates and displays 3 separate Froms and a Service without a single call to the ‘new’ operator anywhere in the solution and, more importantly, without having to pass object references around yourself.

While I find that both fun and useful, the real thing I love about the OpenNETCF.IoC framework (and the SCSF that it’s modeled after) is the implementation of inversion of control through event publication and subscription.

A New Paradigm for Events

In the traditional managed development, an object exposes an event, something like this:

public event EventHandler OnMyEvent;

And when a subscriber wants to get notified of that event, they add a handler delegate like this:

publisherInstance.OnMyEvent += HandleOnMyEvent;

void HandleOnMyEvent(object sender EventArgs args)
{
  // do something useful here
}

That’s all well and good, but in my mind there are two problems with it. First it’s just plain ugly.  I have code in two places, first to attach the event, and second to handle it.  I like to keep related code close together, and this coupling of attaching the handler and the delegate implementation makes that hard (unless you use anonymous delegates). 

The second, and far worse, problem is that it requires that you have the instance of the event publisher to wire this up.  In some cases this is fine, but in others it seems rather pointless.  Let’s go back to one of our early examples of People and Cars and extend it ever so slightly.  We’ll add an event to the Car class :

public delegate void WreckHandler(ICar car);

class Car : ICar
{
  public event WreckHandler OnWreck;
}

And let’s say we have a specialized person – a PoliceOfficer – and he’d like to know any time there is a car wreck.

class PoliceOfficer : Person
{
  public void HandleCarWreck(ICar car) {…}
}

How would we wire this up?  Should we pass every Car instance in town to the officer so he can wire up the event?


class PoliceOfficer : Person
{
  public void HandleCarWreck(ICar car) {…}

  public void WatchCar(ICar car)
  {
    car.OnWreck += HandlerCarWreck;
  }
}

When would we call this?  Every time a Car instance is created?  How would the new Car instance know about the PoliceOfficer?  What if we have multiple Officers?  You can see that this gets real ugly, real fast.  Wouldn’t it be nice if any PoliceOfficer could just listen for the OnWreck event globally and any time any Car instance raised it, he would get notified?  Well that’s what the OpenNETCF.IoC framework’s eventing structure is all about. You publish and subscribe to events based on a unique string name for the event of interest.

So for the event publisher, the Car in this case, we use the same event definition but we add a simple attribute:


class Car : ICar
{
  [EventPublication(“CarWreck”)]
  public event WreckHandler OnWreck;
}

The important piece here is the text string that is sent in to the EventPublication attribute.  It can be any string at all, but it’s that string that event subscribers will use.

Over on the subscriber end it, hooking up the event looks like this:

class PoliceOfficer : Person
{
  [EventSubscription(“CarWreck”, ThreadOption.Caller)]
  public void HandleCarWreck(ICar car) {…}
}

Notice that I’m using the same text string in both.

Now there are a few important notes on using events in the OpenNETCF.IoC framework.  First all of the objects (publishers and subscribers) have to be actually in the framework (in either the Items or Services collection).  In fact with the version of the Framework that ships as I write this, the objects actually have to be created by the framework.  This means that if you create the object manually and then use the Add method to get it into the collection (as opposed to calling AddNew or using an InjectionConstructor or ServiceDependency), then the events won’t get wired up.  I intend to fix this in a future version, but if you pull down the code today, be aware of that limitation.

The second note is in relation to the subscriber.  You’ll see that the EventSubscription attribute takes a ThreadOption as a second parameter.  The idea behind this parameter is that it should dictate the thread on which the handler runs – either in the context of the caller or in the context of the UI.  Well that attribute, for now, is just a placeholder.  It’s not actually used anywhere, so don’t be surprised if your worker thread raises an event and your subscriber tries to update the UI and gets an exception whining about the use of Control.Invoke.  Again, this is something I intend to complete but when I looked at the options of releasing the framework either earlier with a few missing features or later and feature complete, I thought that just getting it out would be a lot more useful.


Next up: Looking at the performance implications of all of this IoC and DI stuff

2 thoughts on “Part III: The OpenNETCF.IoC Framework: Events”

  1. Great post, thanks.

    I need some clarification though. If I understand correctly, at time when object is requested the IoC framework will do all the wireup: create dependent objects and services and attach events.
    It is also possible to lazy create items and services creation. What will happen if object tree is rather complex (deep enough), while some objects in the tree should be lazy created and some not?

    Like

  2. You are correct, the framework will create objects, services and wire up events (assuming you have all of the proper attributes to tell it to do so). Only Services support lazy creation – Items get creates with the call to AddNew. The framework attempts to walk the tree and continue to create necessary objects. You can look at the unit tests that ship with the framework and see that I tested this to some degree, though not to any great depth, and if an object that needs auto-creation depends on some object that isn’t you’re likely going to just get a NullReferenceException – there’s no way that the framework could deal with that. Feel free to extend the unit tests for more complex cases.

    One thing the framework does *not* do (at least not yet) is to look for circular dependencies. I felt that leaving that to the developer made more sense that eating CPU cycles. I figure that if you have them, you’ll find them fast when you get a stack overflow during testing.

    Like

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