lambda expressions in C#? - c#

I'm rather new to these could someone explain the significance (of the following code) or perhaps give a link to some useful information on lambda expressions? I encounter the following code in a test and I am wondering why someone would do this:
foo.MyEvent += (o, e) => { fCount++; Console.WriteLine(fCount); };
foo.MyEvent -= (o, e) => { fCount++; Console.WriteLine(fCount); };
My instinct tells me it is something simple and not a mistake, but I don't know enough about these expressions to understand why this is being done.

The lambda expression (o, e) => { fCount++; Console.WriteLine(fCount); } is interpreted as an anonymous method that takes two arguments o, e (whose types are inferred from the delegate type used for MyEvent and returns void. It captures the fCount variable in the body of the enclosing method (if it's a local variable). The += operator will subscribe the anonymous method to the event and the -= unsubscribes a delegate from an event.
Update (re: concerns about delegate instance equality):
It's important to know that it's not a good idea to try to unsubscribe from the event like that. The language specification, permits, but doesn't require that the delegate in the second line to be equal to the delegate from the first line. That is, the compiler is allowed to treat the two anonymous function bodies as if it was the same function or if it wasn't (because the anonymous function body is semantically identical and the set of captured variables is equal too). Even if it works as expected in your compiler, it might break in the next version. To quote the C# Language Specification on that:
C# Language Specification (Section 7.9.8 Delegate equality operators):
Invocation list entries produced from evaluation of semantically identical anonymous-function-expressions with the same (possibly empty) set of captured outer variable instances are permitted (but not required) to be equal.
If the compiler treats the two anonymous function expressions as equal, the second line will unsubscribe the previous anonymous method from the event. If it doesn't the second line will not do anything special (it's not an error to unsubscribe a delegate from an event invocation list if it doesn't already exist in the list).

Here is a great video about lambda expressions in C#. The video is 2 years old, but it gets users up to speed on the functionality that was relatively new at that time. The content you're interested begins around 3:02.

It is a mistake. It's adding an anonymous delegate to the MyEvent event, but trying to remove a different instance of the same anonymous delegate. Since the instance is probably always different, it may never actually remove the original delegate, which is almost certainly not what you want.

It is an implementation of an event handler using a lambda expression. The advantag is that it is a) inline, i.e. no additional function declaration is required and b) that it can draw on the variables declared in the function where you found this declaration (using closures).

It looks like he's thinking that's equivalent to:
var eh = new EventHandler(delegate(object o, EventArgs e)
{ fCount++; Console.WriteLine(fCount); };
foo.MyEvent += eh;
foo.MyEvent -= eh;
But the unregistering isn't going to work as expected since it has no way of knowing its supposed to be referring to the registered delegate.
The syntax he's using for adding the handler is just a shorter way of attaching an anonymous delegate to an event and is pretty popular syntax, but not something I'd recommend using if you also have to unregister it.

Lambda expressions are a syntactic shorthand to declare a function. So,
(o, e) => { fCount++; Console.WriteLine(fCount); }
means a function that takes two arguments and executes two statements.
As for the code snippet, the unsubscribe '-=' will not work because it is shorthand for:
foo.MyEvent += new EventHandler( (o, e) => { fCount++; Console.WriteLine(fCount); } );
foo.MyEvent -= new EventHandler( (o, e) => { fCount++; Console.WriteLine(fCount); } );
This is actually a resource leak. Instead store a reference to the handler and use that to perform the subscribe and unsubscribe:
var handler = new EventHandler( (o, e) => { fCount++; Console.WriteLine(fCount); } );
foo.MyEvent += handler;
foo.MyEvent -= handler;

Related

How to subscribe to an event with a delegate

I would like to subscribe to an event so that when the event fires I can execute a delegate or anonymous function.
Subscribing to events with methods is easy I can just type the method name, this works fine:
UnityEngine.UI.Toggle tgl;
tgl.onValueChanged += myMethod;
But I cannot subscribe a delegate using the same syntax. This will not work:
tgl.onValueChanged += delegate{ Debug.Log("Bang!"); };
I researched this Q&A which suggested I try the following approach but this is also not working:
tgl.onValueChanged += (object sender, EventArgs e) => { Debug.Log("Bang!"); };
How can I make this work?
You need to look at what type onValueChanged is, before trying to subscribe to it. This is its declaration, taken from here.
public UI.Toggle.ToggleEvent onValueChanged;
Its type is a ToggleEvent, which is a class, not an event nor a delegate. Therefore, you cannot use the += operator on it.
You should call AddListener, like the examples did:
tgl.onValueChanged.AddListener(delegate { ... })

Detach event handler after attaching method with passed parameter

I need to pass a parameter (in C#) to an event handler and then be able to detach the event handler.
I attach the event handler and pass the parameter:
_map.MouseLeftButtonUp += (sender, e) => _map_MouseLeftButtonUp2(sender, e, showResultsWindow);
The event is called as expected. I try to detach the event handler:
_map.MouseLeftButtonUp -= (sender, e) => _map_MouseLeftButtonUp2(sender, e, showResultsWindow);
The code executes without error, but does not seem to detach.
If I attach the event handler the more conventional way (without passing a parameter):
_map.MouseLeftButtonUp+=_map_MouseLeftButtonUp;
and detach
_map.MouseLeftButtonUp -= _map_MouseLeftButtonUp;
everything works as expected
Detaching the event handler (that takes a parameter) via the more conventional way
_map.MouseLeftButtonUp -= _map_MouseLeftButtonUp2;
gives me an error saying the delegates don't match (which makes sense)
So my question is: Why is the event handler not really being detached when I pass a parameter, and is there a way to circumvent this problem.
When you create a lambda (anonymous) function, you're actually creating a new function each time.
The reason your first two lines don't work is because they are two completely different functions that just happen to do the same thing. The correct way to detach would be to have subscribe and unsubscribe from a function, as you've already figured out.
An alternative, that's probably not worth it, is to save your lambda to a variable.
Action<object, MouseButtonEventArgs> myEventMethod = (sender, e) => _map_MouseLeftButtonUp2(sender, e, showResultsWindow);
_map.MouseLeftButtonUp += myEventMethod;
// ...
_map.MouseLeftButtonUp -= myEventMethod;
The reason is that two delegates are not equal:
// You add one delegate instance
_map.MouseLeftButtonUp += (sender, e) => _map_MouseLeftButtonUp2(sender, e, showResultsWindow);
// ..And try to remove another one (not previous!) That's why the first delegate remains unremoved
_map.MouseLeftButtonUp += (sender, e) => _map_MouseLeftButtonUp2(sender, e, showResultsWindow);
You can convince youself by
var x = (sender, e) => _map_MouseLeftButtonUp2(sender, e, showResultsWindow);
var y = (sender, e) => _map_MouseLeftButtonUp2(sender, e, showResultsWindow);
if (Object.Equals(x, y)) { // <- You expected this behaviour
...
}
else { // <- Alas, this is a real situation: x != y
...
}
The reason of such a behaviour is that when Object.Equals is not overridden (and in case of delegates it's not) Object.Equals works as Object.RefrenceEquals does, which checks instances referenses (addresses). Sure, that addresses of x and y are different as well as two your delegates

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

Can you see downsides to this one-liner other than the fact that multiple uses of it would violate the DRY principle? It seems straightforward but the fact that I haven't seen others propose it makes me wonder if there's a downside to it.
This bit of code creates a WeakReference to a method and then registers an event handler that invokes the reference's target.
SomeEvent += (sender, e) => ((Action)(new WeakReference((Action)ProcessEvent)).Target)();
Thanks,
Ben
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.
Its not very readable. And if you have to debug it by stepping through, any one of those actions could fail, but that single line would fail. Also, you'd only get that single line referenced in a stack trace.
You generally want to avoid doing too many things in a single line for maintainability.

C# - anonymous functions and event handlers

I have the following code:
public List<IWFResourceInstance> FindStepsByType(IWFResource res)
{
List<IWFResourceInstance> retval = new List<IWFResourceInstance>();
this.FoundStep += delegate(object sender, WalkerStepEventArgs e)
{
if (e.Step.ResourceType == res) retval.Add(e.Step);
};
this.Start();
return retval;
}
Notice how I register my event member (FoundStep) to local in-place anonymous function.
My question is: when the function 'FindStepByType' will end - will the anonymous function be removed automatically from the delegate list of the event or I have to manually remove it before steping out the function? (and how do I do that?)
I hope my question was clear.
Your code has a few problems (some you and others have identified):
The anonymous delegate cannot be removed from the event as coded.
The anonymous delegate will live longer than the life of the method calling it because you've added it to FoundStep which is a member of this.
Every entry into FindStepsByType adds another anonymous delegate to FoundStep.
The anonymous delegate is a closure and effectively extends the lifetime of retval, so even if you stop referencing retval elsewhere in your code, it's still held by the anonymous delegate.
To fix this, and still use an anonymous delegate, assign it to a local variable, and then remove the handler inside a finally block (necessary in case the handler throws an exception):
public List<IWFResourceInstance> FindStepsByType(IWFResource res)
{
List<IWFResourceInstance> retval = new List<IWFResourceInstance>();
EventHandler<WalkerStepEventArgs> handler = (sender, e) =>
{
if (e.Step.ResourceType == res) retval.Add(e.Step);
};
this.FoundStep += handler;
try
{
this.Start();
}
finally
{
this.FoundStep -= handler;
}
return retval;
}
With C# 7.0+ you can replace the anonymous delegate with a local function, achieving the same effect:
public List<IWFResourceInstance> FindStepsByType(IWFResource res)
{
var retval = new List<IWFResourceInstance>();
void Handler(object sender, WalkerStepEventArgs e)
{
if (e.Step.ResourceType == res) retval.Add(e.Step);
}
FoundStep += Handler;
try
{
this.Start();
}
finally
{
FoundStep -= Handler;
}
return retval;
}
Below is approach about how unsubscribe event in anonymous method:
DispatcherTimer _timer = new DispatcherTimer();
_timer.Interval = TimeSpan.FromMilliseconds(1000);
EventHandler handler = null;
int i = 0;
_timer.Tick += handler = new EventHandler(delegate(object s, EventArgs ev)
{
i++;
if(i==10)
_timer.Tick -= handler;
});
_timer.Start();
No, it will not be removed automatically. In this sense, there's not a difference between an anonymous method and a "normal" method. If you want, you should manually unsubscribe from the event.
Actually, it'll capture other variables (e.g. res in your example) and keep them alive (prevents garbage collector from collecting them) too.
When using an anonymous delegate (or a lambda expression) to subscribe to an event does not allow you to easily unsubscribe from that event later. An event handler is never automatically unsubscribed.
If you look at your code, even though you declare and subscribe to the event in a function, the event you are subscribing to is on the class, so once subscribed it will always be subscribed even after the function exits. The other important thing to realize is that each time this function is called, it will subscribe to the event again. This is perfectly legal since events are essentially multicast delegates and allow multiple subscribers. (This may or may not be what you intend.)
In order to unsubscribe from the delegate before you exit the function, you would need to store the anonymous delegate in a delegate variable and add the delegate to the event. You should then be able to remove the delegate from the event before the function exits.
For these reasons, if you will have to unsubscribe from the event at some later point it is not recommended to use anonymous delegates. See How to: Subscribe to and Unsubscribe from Events (C# Programming Guide) (specifically the section titled "To subscribe to events by using an anonymous method").

How do I deregister an anonymous handler?

C# 2.0 has a neat feature called anonymous functions. This is intended to be used mostly with events:
Button.Click += delegate(System.Object o, System.EventArgs e)
{ System.Windows.Forms.MessageBox.Show("Click!"); };
Now, suppose that Button is a static member, then adding delegates to it would count as unmanaged resources. Normally, I would have to deregister the handler before regestring it again. This is a pretty common use case for GUI programming.
What are the guidelines with anonymous functions? Does the framework deregrister it automatically? If so, when?
No, anonymous functions will not get deregistered automatically. You should make sure to do it yourself, if the event should not be hooked up for the whole lifetime of your application.
To do this, of course, you would have to store the delegate reference, to be able to de-register it.
Something like:
EventHandler handler = delegate(System.Object o, System.EventArgs e)
{ System.Windows.Forms.MessageBox.Show("Click!"); };
Button.Click += handler;
// ... program code
Button.Click -= handler;
Also, see this question.
If I recall correctly (and I can recall where I read this) inline anonymous delegates cannot be removed.
You would need to assign to a (static) delegate field.
private static EventHandler<EventArgs> myHandler = (a,b) => { ... }
myButton.Click += myhandler;
...
myButton.Click -= myHandler;

Categories

Resources