This post originated from an RSS feed registered with .NET Buzz
by Udi Dahan.
Original Post: .Net 2.0 Generics, Anonymous Methods, and Delegate inference bug
Feed Title: Udi Dahan - The Software Simplist
Feed URL: http://feeds.feedburner.com/UdiDahan-TheSoftwareSimplist
Feed Description: I am a software simplist. I make this beast of architecting, analysing, designing, developing, testing, managing, deploying software systems simple.
This blog is about how I do it.
I'm working on this system that allows the user to perform certain tasks on a map. For instance, building a route on the map is performed by quite simply clicking on the map to add waypoints. This action is done as a part of the RouteForm data entry - on the form there is a button that, when clicked, changes the map's state to accept user input (the polyline map tool is selected). Of course, the user could have a number of these forms open at any time. Obviously, we'd need to route selected on the map to be passed back to the originating form, and not a different open RouteForm.
In this case, we'd have our RouteForm expose a "NeedPolyline" event. We wouldn't want our forms or controlling logic (presenters) to be dependent on the map implementation, so we make heavy use of the command pattern to transfer data between them.
So, as a result of the "NeedPolyline" event raised by the RouteForm, the RouteController needs to communicate that it needs a new polyline to be created. This is done by activating the "New" command and passing "typeof(Polyline)" in the event args "EntityType" property. When the MapController gets called back on the command, it activates the relevant map tool. When the user finishes selecting the route on the map (signalled by a right click), the map controller needs to take the polyline from the map control and pass it back into the application. This is done by activating the "Open" command, and passing the polyline as a parameter to the event args. What the RouteController needs to do when its called back on that command is to pass the polyline back to the RouteForm that initiated the whole deal. Ay, there's the rub.
Well, there's an elegant solution that uses the new features of .net 2.0 to do just that, or so I thought. Here's the code:
private void RouteForm_OnNeedPolyline(object sender, EventArgs e)
{
IRouteForm f = sender as IRouteForm;
if (f == null) return;
Commands.Open.Activated += this.GetOpenPolylineCallbackFor(f);
Commands.New.Activate(this, new NewEventArgs(typeof(Polyline)));
}
private EventHandler<OpenEventArgs> GetOpenPolylineCallbackFor(IRouteForm f)
{
return delegate(object sender, OpenEventArgs e)
{
Polyline p = e.Entity as Polyline;
if (p == null) return;
The nicest thing about the above code is that the management of which form requested the polyline is automatically handled - I don't have to write any code that pipes the event back to the originating form. There's only one eensy-weensy problem. Unsubscribing from the event doesn't work - the code "Commands.Open.Activated -= this.GetOpenPolylineCallbackFor(f);" doesn't do anything. In which case, only the first RouteForm works correctly, since the event is piped back to all forms ever opened.
Is this a bug? Well, it is in my book. I don't get how the subscription can work while the inverse doesn't. I know that there are workarounds - I've already implemented them and moved on. But I think that there's a real missed opportunity here. This is the kind of code .net 2.0 is supposed to support - generic, concise, elegant.
I really hope that this gets rolled into SP1 of VS2005. I'd really hate to have to wait 3 years for a fix for this (re: VS2003 sp1).