views:

116

answers:

4

I have a lot of code like the following, where I explicitly implement some events required by an interface.

public class IMicrowaveNotifier {
  event EventHandler<EventArgs> DoorClosed;
  event EventHandler<EventArgs> LightbulbOn;
  // ...
}

public class Microwave : IMicrowaveNotifier {
  private EventHandler<EventArgs> _doorClosed;
  event EventHandler<EventArgs> IMicrowaveNotifier.DoorClosed {
    add { lock (this) _doorClosed += value; }
    remove { lock (this) _doorClosed -= value; }
  }

  private EventHandler<EventArgs> _lightbulbOn;
  event EventHandler<EventArgs> IMicrowaveNotifier.LightbulbOn {
    add { lock (this) _lightbulbOn += value; }
    remove { lock (this) _lightbulbOn -= value; }
  }

  // ...
}

You can see that much of this is boilerplate. In Ruby I'd be able to do something like this:

class Microwave
  has_events :door_closed, :lightbulb_on, ...
end

Is there a similar shorter way of removing this boilerplate in C#?


Update: I left a very important part out of my example: namely, the events getting implemented are part of an interface, and I want to implement it explicitly. Sorry for not mentioning this earlier!

+10  A: 

Try this:

public class Microwave {
    public event EventHandler<EventArgs> DoorClosed;
    public event EventHandler<EventArgs> LightbulbOn;
}

This code leverages C#'s field-like event syntax:

When compiling a field-like event, the compiler automatically creates storage to hold the delegate, and creates accessors for the event that add or remove event handlers to the delegate field.

In C# 1, 2, and 3 this code will compile down to just what you have above. In C# 4 you will get functionally equivalent code that doesn't use explicit locks. Either way you can use this shortcut without changing the consumers of this type.

Update: Unfortunately, the C# compiler does not allow you to use field-like events for explicit interface implementation. If you try you will get this compilation error:

An explicit interface implementation of an event must use event accessor syntax

Update: It's too bad that an explicit interface implementation requires the use of event accessor syntax. It would be kind of cool if C# added the ability to create automatically implemented field-like events like this:

event EventHandler<EventArgs> IAppliance.DoorClosed { add; remove; }

But this syntax is already wordier than the existing field-like event syntax and would only be applicable in cases where an interface member was being explicitly implemented. The best thing I think would be if the compiler would simply allow us to do this:

event EventHandler<EventArgs> IAppliance.DoorClosed;
Andrew Hare
@Andrew: Very sorry, but I left an important piece of the puzzle out of my question. Specifically, I'm using explicit interface implementation for the events. This seems to require using `add`/`remove` directly. I made the update above.
Damien Wildfire
@Andrew: Thanks for the update. That's pretty much the same conclusion I reached. Bummer! Is there any way that extension methods would help here?
Damien Wildfire
So it seems the answer to your question is no: C# will not allow you to avoid the repetition.
Qwertie
@Damien - Sorry dude! I think your only option is to manually create the backing fields and the `add` and `remove` accessors. It's too bad really - perhaps C# 5 will give us something like this: `event EventHandler<EventArgs> IAppliance.DoorClosed { add; remove; }`
Andrew Hare
A very strange restriction, IMO, as you can implement properties in interfaces by meant of automatic properties. I'd say open a Connect suggestion for this.
Pavel Minaev
A: 

I am not sure what Lock does as I am kind of new, but you can connect all of the controls or whatever is calling those events to only one event. In that event just do a if statement to check who is sending it.

It would look much neater I would think, but still require a some amount of work I guess.

Dinoo
His question was poorly titled. His issue is with the verbosity of the code, not the events firing frequently. FWIW, I had expected to see a question to which this would have been an answer.
Adam Robinson
@Adam, @Dinoo: I've edited the title. Hopefully this is less confusing now. Thanks for the heads up.
Damien Wildfire
A: 

Write a code snippet for it and use a shortcut. Just like when you use if, for, foreach{tab}{tab}.

gbogumil
A: 

Code snippets as suggested by gbogumil will save some time. Alternately, if there's a specific interface you find yourself implementing regularly that requires this, is it possible for you to create an abstract base class?

Chris