Recently, I was thinking about one of the cases were you have to use the IDisposable pattern, the case were you need to unsubscribe from events and delegates to allow your object to get disposed by the Garbage Collector (some people miss that point), and this made me think about my hobby of overusing Lambda Expressions and if that might also cause similar problems. So I did a bunch of tests today and learned a lot of things and came up with a workaround that would make me avoid using the IDisposable pattern when all I need it for is to unsubscribe from events.

Tiny Disclaimer

The following information is a combination of things I read on StackOverflow and by reading and understanding the compiled (MSIL) code.
Some answers on StackOverflow might have some errors, and my understanding of MSIL isn’t that good, so take that info with a grain of salt and I encourage you to do your own tests to discover more about Lambda Expressions as (of course) I didn’t cover all the cases here.

The not-so-known Problem

First of all let me discuss the problem that some people might fall for.
Let’s say you have a WPF application that’s made up of two windows, WindowA and WindowB, and you have a button that causes a new instance of WindowB to be created and showed when pressed, and for some reason WindowB needs to subscribe to one of the events in WindowA, now if WindowB got closed by the user (or programmatically) the object holding WindowB wont get disposed even though the UI is gone now, and that’s because one of the events in WindowA still has a reference to a method in WindowB’s class!

An experienced developer would solve this problem by making WindowB implement the IDisposable interface and write a Dispose method that unsubscribes from all the events that it doesn’t own and make sure that this Dispose method is called whenever WindowB gets closed (one way to do this is to call is from the Window.Closing event handler).

But I was worrying about a bigger problem …

Overusing Lambda Expressions

Since the moment I got to know Lambda Expressions and recognize their power, I’ve been using them everywhere like crazy, apart from LINQ queries I’ve used them in multi-threading (defining the ThreadStart inline) and in simple Event Handlers (e.g.: CloseBtn.Click += (s, e) => this.Close();), it’s so crazy that the first version of the code for “MotionDataDisplayer” that’s part of my MotionOverUDP project was all implemented inside the constructor of MainWindow :D

So I started to worry if all these Lambda Expression might be holding instances of objects that should’ve been disposed and maybe even have these pile up over time and cause a memory leak! I remembered that I read before that the C# compiler generates classes for lambda expressions to capture local variables and thus preserve their context (that’s how they can be called from outside the scope they were created and still run), this made me worry even more about accidentally having references of object I though I disposed!

Behind the Scenes!

With all that worrying and an empty Friday, I decided to just fire up a new project on Visual Studio to test how things work and also did some reading over at StackOverflow and other places and discovered the following …

If you have a lambda expression that doesn’t use any local variables in it’s body, then no classes are generated and only a method in the same class will be generated as with these cases:

01: int x = 8;
 02:
 03: public static void Main(string[] args)
 04: {
 05:     Action a1 = () => DoSomething();
 06:     a1();
 07:  
 08:     Action a2 = () => DoSomething(x);
 09:     a2();
 10:  
 11:     Action<int> a3 = (n) => DoSomething(n);
 12:     int y = 4;
 13:     a3(y);
 14: }

So in the case of accessing class variables or instance variables from lambda expressions, the generated method just uses that same class/instance variable, there is no extra reference to the same object.

In case of accessing a local variable inside the body of a lambda expression, the compiler will generate a nested class with a weird name, this class will have the method you wrote in the lambda expression and a field for every local variable you used in the expression, and any read or write to that local variable in the calling function is modified so that it’s done on the field in that generated class as these variable don’t actually exists in the calling function anymore!

It’s quite weird but actually this makes your code work exactly the way you would expect, take a look at this example:

 1: SomeObject obj = new SomeObject();
 4: Action a = () => DoSomething(obj);
 5: obj = null;
 6: a(); // NullReferenceException!

At first I though that “DoSomething” would work fine as the class generate by the compiler would have another reference to my “SomeObject” but that’s not the case due to that weird extra piece of information I wrote above.
So actually happens here is that the compiler generates a class (let’s call it GenClass), then generates a field “GenClass.obj” of type “SomeObject” and a void method with no paramters (let’s call it GenMethod) and the body of that method will be “DoSomething(obj);” (apparently is can just access “DoSomething” because the generated class a nested class).
So here is how it would (roughly) look like if I were to convert the compiled code back to C#: (didn’t actually try that as I expect some decompilers to be smart and show me the lambda expression)

 1: GenClass gen = new GenClass();
 2: gen.obj = new SomeObject();
 3: Action a = new Action(gen.GenMethod);
 4: gen.obj = null;
 5: a(); // NullReferenceException!

I think now it’s clear why it behaved the way it did, my guess about the behavior was wrong because I had incomplete information about what happens behind the scenes (I thought there was going to be two fields referencing the same object), but I think a beginner who doesn’t have any idea how lambda expressions work behind the scenes would’ve guessed that behavior, and I think that’s why the team responsible for C# came up with the decision to let the compiler do these crazy things behind the scenes.
I think this makes the C# compiler even smarter than it already is, and that smartness is what makes me love C# :)

So … is it ok to overuse lambdas?

yeah, kind of …
If you were just worrying about having extra references to your object that would block garbage collection, then you don’t have to worry, because the classes generated for lambdas by the compiler don’t have an extra reference, they end up using the same one (as seen in the previous 2 cases), so when you nullify your reference, the object just get destroyed and any lambda that depended on that object will no longer work.

But take care!
I made one final test that showed me that things wont always be nice and fun, take a look at this code:

 01: static Action action;
 02:
 03: public static void Main(string[] args)
 04: {
 05:     SomeObject obj = CreateGarbage();
 06:     obj = null;
 07:     action(); // Still works!!!
 08: }
 09:
 10: public static SomeObject CreateGarbage()
 11: {
 12:     SomeObject garbage = new SomeObject();
 13:     action = () => garbage.DoSomething();
 14:     return garbage;
 15: }

So yeah, this is quite confusing …
First of all you have to note that “garbage” and “obj” are two references for the same object, if we would comment out line 7 and 13, both “garbage” and “obj” would eventually become nulls and the object would get destroyed, the first because we moved out of it’s scope so the runtime automatically nullifies it and the second was nullified explicitly.
But once you have a lambda accessing “garbage” (a local variable) then the compiler will generate a class and “garbage” will be moved to that class and all access to “garbage” will be changed so it accesses the field inside the generated class, so the code will be changed to something like this:

 01: static Action action;
 02:
 03: public static void Main(string[] args)
 04: {
 05:     SomeObject obj = CreateGarbage();
 06:     obj = null;
 07:     action(); // Still works!!!
 08: }
 09:
 10: public static SomeObject CreateGarbage()
 11: {
 12:     GenClass gen = new GenClass();
 13:     gen.garbage = new SomeObject();
 14:     action = new Action(gen.GenMethod);
 15:     return gen.garbage;
 16: }

So what happens here is that “gen” is referenced by “action” so after the “GenerateGarbage” finishes execution “gen” will not be nullified, and back in the Main method even after you nullify “obj” you still have “gen.garbage” referencing the same object, so the object doesn’t get destroyed and “action” still works!

Conclusion

So let’s conclude this before our heads explode here …

As everything in programming languages, you always have to take care about the way you use the language’s features, in the usual case everything will go fine, but in certain cases things can go bad.
In the case of the WPF Applications it probably wont be worth it to throw away the event unsubscribing that happens in the Dispose method in favor of using Lambda Expressions for the Event Handlers as you still have to nullify your stuff to allow them to get collected (instead of calling Dispose then nullifying).
But imagine a case where you have a game, and you are constantly firing and destroying projectiles, and when you initialize a projectile you hook up one of its methods to an external event, it might be better idea to hook it up using a lambda expression (this.SomeEvent += (s, e) => projectile.SomeMethod()) instead of the usual way as it will allow you to avoid using the IDisposable pattern, and as you are destroying the projectiles you already nullify them as part of the game logic, so it will just work and you wont have to make the projectiles unsubscribe from any events, and it might also make your code look cleaner if you don’t really need the “sender” and “EventArgs” parameters in the method you want to hook up.

I’m sure a lot of developers will disagree with this “hack”, but personally I like avoiding the IDisposable pattern whenever I can because you always have to remind yourself to implement it, similar to how you have to always remind yourself to free unused memory in C++.

Anyways, I hope this deep look into Lambda Expressions was useful for you and made you figure out the line between good usage of lambdas and bad usage of lambdas :)