Weak Event Handler Model for Use with Lambdas

One Liner: WeakReference-to-a-Lambda Event Handler

I don't think that pattern does what you expect. Are you trying to prevent the event from holding a reference to the current object so as to prevent memory leaks? The lambda expression will capture the value of this in order to evaluate ProcessEvent (assuming ProcessEvent is an instance method), so you will still have the leak. This code is the same as doing SomeEvent += (sender, e) => ProcessEvent();.

You may be trying to do something more like this (which also isn't what you want):

var reference = new WeakReference((Action)ProcessEvent);
SomeEvent += (sender, e) => ((Action)reference.Target)();

Now the lambda expression will capture the WeakReference, so you won't have a strong reference to this. Unfortunately, nothing else is referencing the delegate created from ProcessEvent, so it will be removed on the next GC even if this is still alive. (This also doesn't check for Target being null).

You could try something like this:

public EventHandler MakeWeakHandler(Action action, Action<EventHandler> remove)
{
var reference = new WeakReference(action.Target);
var method = action.Method;
EventHandler handler = null;
handler = delegate(object sender, EventArgs e)
{
var target = reference.Target;
if (target != null)
{
method.Invoke(target, null);
}
else
{
remove(handler);
}
};
return handler;
}

and then use it like this:

SomeEvent += MakeWeakHandler(ProcessEvent, h => SomeEvent -= h);

That will keep a weak reference to the receiver of ProcessEvent, and will automatically remove the event handler from the event after it has been collected, which should prevent memory leaks as long as the event is raised regularly.

WeakEventManager with event name lambda expression and custom event accessors

With .NET 4.6 you can now use the nameof() expression:

WeakEventManager<IMyGrid, MyEventArgs>.AddHandler(myGrid, nameof(IMyGrid.MouseDown), OnMouseDown);

UnHooking Events with Lambdas in C#

Unforutantely there is not a great way to do this. You are really stuck with one of two options

  • Use a method as you described
  • Assign the lambda to a variable and use the variable to add / remove the event

Can using lambdas as event handlers cause a memory leak?

Yes, save it to a variable and unhook it.

DelegateType evt = (o, e) => { firedCount++; Console.Write(firedCount); };
foo.AnEvent += evt;
foo.MethodThatFiresAnEvent();
foo.AnEvent -= evt;

And yes, if you don't, you'll leak memory, as you'll hook up a new delegate object each time. You'll also notice this because each time you call this method, it'll dump to the console an increasing number of lines (not just an increasing number, but for one call to MethodThatFiresAnEvent it'll dump any number of items, once for each hooked up anonymous method).

Best practices of using lambda expressions for event handlers

It's a perfectly reasonable idea - but in this particular case, I would use an anonymous method instead:

txtLogin.LostFocus += delegate
{
txtLogin.Text = "Login...";
txtLogin.ForeColor = SystemColors.InactiveCaptionText;
};

The benefit is that you don't have to specify the parameters - which makes it clearer that you're not using them. This is the only advantage that anonymous methods have over lambda expressions.

The performance hit is almost always going to be negligible. The inability to remove them afterwards is a very real problem if you do need to be able to remove the handler, but I find that often I don't. (Reactive Extensions has a nice approach to this - when you subscribe to an observable sequence, you're given back an IDisposable which will remove the subscription if you call it. Very neat.)

How to unsubscribe from an event which uses a lambda expression?

If you need to unsubscribe from an event, you need an instanced reference. Unfortunately, that means you can't use that particular syntax.

Anonymous method for event handler not a leak?

Whenever you add a delegate to an event handler, you should remove it later, right?

Not necessarily, no. Often you want the event handler to stay valid for as long as the event itself can be raised - that's certainly very common with UIs.

Is this really an okay practice?

Absolutely, so long as you don't need to unhook the handler. Think about the point at which you'd unhook the event handler. If it's "when the form (or button, or whatever) is elegible for garbage collection" then what benefit is there in removing the handler? Just let it be garbage collected with the form...



Related Topics



Leave a reply



Submit