5

Consider the situation in which you want to subscribe to an event for one and only one notification. Once the first notification lands, you unsubscribe from all future events. Would the following pattern present any memory issues? It works, but I wasn't sure if the self-referencing closure could keeps things around in memory longer than desired.

public class Entity
{
    public event EventHandler NotifyEvent;
}

// And then, elsewhere, for a listen-once handler, we might do this:
Entity entity = new Entity();
Action<object, EventArgs> listener = null;
listener = (sender, args) =>
{
    // do something interesting
    // unsubscribe, so we only get 1 event notification
    entity.NotifyEvent -= new EventHandler(listener);
};
entity.NotifyEvent += new EventHandler(listener);

Note that you have to declare 'listener' and assign a value (null). Otherwise the compiler complains about 'Use of unassigned local variable listener'

Matt
  • 41,216
  • 30
  • 109
  • 147
  • You may make your code more expressive by enclosing the part of your code starting with `Action listener = null;` in braces. But I am not sure if this would make the life easier for the garbage collector: after all, you anyway don't use your variable any more! – Vlad Nov 03 '11 at 16:12

2 Answers2

6

There is nothing wrong with this pattern. It's the very same pattern I and many others use for assigning and removing a lambda expression to an event handler.

JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
  • A question about this code: Could the sender be used to do the unsubscribing? Something like (sender as Entity).NotifyEvent -= new EventHandler(listener) also inside the lamba expression, or could it be some side issues? – Ricardo Amores Nov 03 '11 at 16:10
  • @RickyAH possibly. It would work for some types although I wouldn't recomend doing it. I'm generally very wary of trusting the `sender` portion of the event pattern. It's useful at times but generally I assume it to be an unreliable value – JaredPar Nov 03 '11 at 16:11
4

While I think the general pattern is fine, I wouldn't go through Action<object, EventArgs>. I'd use:

EventHandler listener = null;
listener = (sender, args) =>
{
    // do something interesting
    // unsubscribe, so we only get 1 event notification
    entity.NotifyEvent -= listener;
};
entity.NotifyEvent += listener;
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Thanks for the tip. I actually generally use custom event Delegates anyway, but for the example I just used EventHandler as the event delegate, since more people recognize it. Completely spaced on the Action though, so thanks. (will leave my less-than-ideal example in place to give your answer context, though) – Matt Nov 03 '11 at 16:18