Monday, December 7, 2009

Ensuring lambdas don't leak when passed to EventHandlers

I'm writing a wrapper around a class which outputs results of commands executed into a stream buffer.  I wanted to capture the command text and return that to the caller of my wrapper.  I wanted to use a lambda and clean up my delegate after the command returned.  This contrived code sample shows how to do this improperly and properly:



static void Main()
{
    ExecuteCommand();
    Debug.Assert(CommandExecuted == null);
    ExecuteCommandLeaks();
    //This assert will fail
    Debug.Assert(CommandExecuted == null);
}

static void ExecuteCommandLeaks()
{
    CommandExecuted += new EventHandler<EventArgs>((o, e) => Console.WriteLine("Event called"));

    CommandExecuted.Invoke(new object(), new EventArgs());
}

static void ExecuteCommand()
{
    var commandCapture = new EventHandler<EventArgs>((o, e) => Console.WriteLine("Event called"));
    CommandExecuted += commandCapture;

    CommandExecuted.Invoke(new object(), new EventArgs());

    CommandExecuted -= commandCapture;
}

static EventHandler<EventArgs> CommandExecuted;