Archive for May, 2007

EventHandlerList, key equality, and auto-boxing in C#

I was recently implementing some custom events, and found a couple of good (if old) articles describing how to do this efficiently using EventHandlerList:

Those articles go into why it's nicer to deal with one EventHandlerList instead of many seperate EventHandlers, so read those for more information. For the lazy, here's some code showing how you're supposed to use these things:

C#:
  1. public class MyClass {
  2.     private EventHandlerList Events = new EventHandlerList();
  3.  
  4.     public event EventHandler MyEvent {
  5.         add { Events.AddHandler("MyEvent", value); }
  6.         remove { Events.RemoveHandler("MyEvent", value); }
  7.     }
  8.  
  9.     public event EventHandler MyOtherEvent {
  10.         add { Events.AddHandler("MyOtherEvent", value); }
  11.         remove { Events.RemoveHandler("MyOtherEvent", value); }
  12.     }
  13.  
  14.     protected void OnMyEvent(object sender, EventArgs e) {
  15.         EventHandler handler = (EventHandler) Events["MyEvent"];
  16.         if (handler != null) {
  17.             handler(sender, e);
  18.         }
  19.     }
  20.  
  21.     protected void OnMyOtherEvent(object sender, EventArgs e) {
  22.         EventHandler handler = (EventHandler) Events["MyOtherEvent"];
  23.         if (handler != null) {
  24.             handler(sender, e);
  25.         }
  26.     }
  27. }

Pretty straightforward stuff. When you add an event handler to the list, you associate it with a key, and then when its time to trigger the events, you look for any handlers under the same key. The other day I was putting together something similar, and ran into some unexpected behavior with the keys. I had started by refactoring the magic strings into an enum:

C#:
  1. protected enum MyEvents {
  2.         MyEvent,
  3.         MyOtherEvent
  4.     }

and replaced all the strings with members of that enum. I figured this would work just fine, but the change caused my unit test to fail. Upon debugging, the EventHandlerList was always returning null in my On*Event calls. After some more testing, the pattern became apparent: value types don't work as keys. This was somewhat unexpected, as I've used enums like this in Hashtables all over the place before. After doing a little Reflectoring, the actual search for the key comes down to traversing a linked list with a simple equality test, something like this:

C#:
  1. while (head != null)
  2.     {
  3.         if (head.key == key)
  4.         {
  5.             return head;
  6.         }
  7.         head = head.next;
  8.     }

The culprit ends up being C#'s auto-boxing. The key is stored as an object, so my value types are being boxed on the way in, and therefore == is comparing object identity, not the object values. If EventHandlerList used head.key.Equals(key), everything would have worked how I expected. The solution to rid myself of magic strings now becomes using static objects as my keys, so the object identities will match:

C#:
  1. private static readonly object MyEventKey = new object();
  2. private static readonly object MyOtherEventKey = new object();

That pattern reminds me a lot of enums in Java before it got a enum keyword, which came on the heels of C#'s nice solution to the enumerated type problem. It'd be nice if I could use enums for their intended purpose, but cases like this make me a bit wary. Where else in the .NET framework am I going to find object identity equality where I expect to find object value equality? Is there some rational explanation for this, or is this just a bug?

Comments

Pretty icons using CSS and Mark James’ Silk Icons

I recently saw a post via reddit on Rediscovering the button element about making nice buttons with little icons, and was introduced to the Silk Icons available from Mark James. Mark has released these under a Creative Commons Attribution license, any my UIs will be better for it.

I went through last night and gave a little face-lift to one of my intranet projects, and it looks a lot nicer now. I added icons to buttons and links using CSS.

Here's the css I used:

CSS:
  1. .icon
  2. {
  3.     background-repeat:no-repeat;   
  4.     padding-left:20px;
  5. }
  6.  
  7. .delete-icon
  8. {
  9.     background-image:url('icons/cross.png');
  10. }
  11.  
  12. .edit-icon
  13. {
  14.     background-image:url('icons/pencil.png');
  15. }

and so forth, with a *-icon for the different icons I wanted. Then, I decorated my buttons, links, and what-have-you by adding a class="icon foo-icon" attribute. There are other ways accomplish that with CSS, but I liked this scheme the best. In the end, I have added nothing significant to the markup, but made everything else look a lot nicer:

Silk icon example 3Silk icon example 2Silk icon example

Thanks a lot, Mark!

Comments