views:

211

answers:

7

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.

+10  A: 

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).

Mehrdad Afshari
I think his concern may be with the `-=` side of things, i.e. what is the effect of *removing* the anonymous method from the event? (My understanding is that this *is* a mistake -- .NET will not magically work out that the removed anonymous method is the same as the previously added one, so the event handler will remain hooked up.)
itowlson
Thanks, thats very thorough.
Matt
@itowlson: Clarified the answer to address that issue.
Mehrdad Afshari
A: 

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).

Obalix
+2  A: 

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.

Software.Developer
Thanks, I'll take a look at it.
Matt
+1 for a very good link
Asad Butt
+1  A: 

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.

Gabe
"Since the instance is always different, it never actually removes the original delegate" -> Not always true - see my answer.
Mehrdad Afshari
Fixed, thanks Mehrdad.
Gabe
A: 

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.

kekekela
A: 

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;
Phillip Ngan