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
Why Cannot Ienumerable<Struct> Be Cast as Ienumerable<Object>
How to Write One to Many Query in Dapper.Net
How to Return a Specific Status Code and No Contents from Controller
Convert File Path to a File Uri
How to Pass a Username/Password in the Header to a Soap Wcf Service
Determine If Current Application Is Activated (Has Focus)
Am I Misunderstanding Linq to SQL .Asenumerable()
Entity Framework Thread Safety
Formatting a Double to Two Decimal Places
Why Datetime.Addhours Doesn't Seem to Work
How to Get the Line Number Which Threw Exception
.Net Timezoneinfo from Olson Time Zone
Displayname Attribute VS Display Attribute
Checking If a String Array Contains a Value, and If So, Getting Its Position
How to Programmatically Change Active Directory Password
If Int32 Is Just an Alias for Int, How Can the Int32 Class Use an Int
C# Implementation of Deep/Recursive Object Comparison in .Net 3.5