views:

2038

answers:

5

Why I can’t use lambda expressions while debugging in “Quick watch” window?

+2  A: 

Lambda expressions are not supported by the debugger's expression evaluator... which is hardly surprising since at compile time they are used to create methods (or Expression Trees) rather than expressions (take a look in Reflector with the display switched to .NET 2 to see them).

Plus of course they could form a closure, another whole layer of structure.

Richard
Well, they *might* create methods; they might create `Expression` trees - it depends on the context.
Marc Gravell
Of course, expanded.
Richard
+9  A: 

Lambda expressions, like anonymous methods, are actually very complex beasts. Even if we rule out Expression (.NET 3.5), that still leaves a lot of complexity, not least being captured variables, which fundamentally re-structure the code that uses them (what you think of as variables become fields on compiler-generated classes), with a bit of smoke and mirrors.

As such, I'm not in the least surprised that you can't use them idly - there is a lot of compiler work (and type generation behind the scenes) that supports this magic.

Marc Gravell
+15  A: 

No you cannot use lambda expressions in the watch / locals / immediate window. As Marc has pointed out this is incredibly complex. I wanted to dive a bit further into the topic though.

What most people don't consider with executing an anonymous function in the debugger is that it does not occur in a vaccuum. The very act of definining and running an anonymous function changes the underlying structure of the code base. Changing the code, in general, and in particular from the immediate window, is a very difficult task.

Consider the following code.

void Example() {
  var v1 = 42;
  var v2 = 56; 
  Func<int> func1 = () => v1;
  System.Diagnostics.Debugger.Break();
  var v3 = v1 + v2;
}

This particular code creates a single closure to capture the value v1. Closure capture is required whenever an anonymous function uses a variable declared outside it's scope. For all intents and purposes v1 no longer exists in this function. The last line actually looks more like the following

var v3 = closure1.v1 + v2;

If the function Example is run in the debugger it will stop at the Break line. Now imagine if the user typed the following into the watch window

(Func<int>)(() => v2);

In order to properly execute this the debugger (or more appropriatel the EE) would need to create a closure for variable v2. This is difficult but not impossible to do.

What really makes this a tough job for the EE though is that last line. How should that line now be executed? For all intents and purposes the anonymous function deleted the v2 variable and replaced it with closure2.v2. So the last line of code really now needs to read

var v3 = closure1.v1 + closure2.v2;

Yet to actually get this effect in code requires the EE to change the last line of code which is actually an ENC action. While this specific example is possible, a good portion of the scenarios are not.

What's even worse is executing that lambda expression shouldn't be creating a new closure. It should actually be appending data to the original closure. At this point you run straight on into the limitations ENC.

My small example unfortunately only scratches the surface of the problems we run into. I keep saying I'll write a full blog post on this subject and hopefully I'll have time this weekend.

JaredPar
+1 for the detail... I'll watch out for that blog entry ;-p
Marc Gravell
+1  A: 

Hi,

this might help: Extended Immediate Window for Visual Studio (use Linq, Lambda Expr in Debugging)

All the best, Patrick

Patrick
+1  A: 

You can't use lambda expressions in the Immediate or Watch windows.

You can however use System.Linq.Dynamic expressions, which take the form .Where("Id = @0", 2) - it doesn't have the full range of methods available in standard Linq, and doesn't have the full power of lambda expressions, but still, it's better than nothing!

Stuart