为什么我不能在"快速监视"窗口中调试时使用lambda表达式?
UPD:另见
http://blogs.msdn.com/b/jaredpar/archive/2009/08/26/why-no-linq-in-debugger-windows.aspx
http://blogs.msdn.com/b/jaredpar/archive/2010/06/02/why-is-linq-absent-from-debugger-windows-part-2.aspx
不,你不能在watch/locals/immediate窗口中使用lambda表达式.正如马克所指出的那样,这非常复杂.我想进一步深入探讨这个话题.
大多数人在调试器中执行匿名函数时没有考虑的是它不会出现在vaccuum中.定义和运行匿名函数的行为改变了代码库的底层结构.一般而言,特别是从即时窗口更改代码是一项非常困难的任务.
请考虑以下代码.
void Example() { var v1 = 42; var v2 = 56; Funcfunc1 = () => v1; System.Diagnostics.Debugger.Break(); var v3 = v1 + v2; }
此特定代码创建一个闭包以捕获值v1.只要匿名函数使用在其范围之外声明的变量,就需要关闭捕获.对于所有意图和目的,此函数中不再存在v1.最后一行实际上看起来更像是以下内容
var v3 = closure1.v1 + v2;
如果函数Example在调试器中运行,它将在Break行停止.现在假设用户在观察窗口中输入以下内容
(Func)(() => v2);
为了正确执行它,调试器(或更合适的EE)需要为变量v2创建一个闭包.这很难但并非不可能.
真正使EE成为一项艰巨的工作的是最后一行.现在应该如何执行该行?对于所有意图和目的,匿名函数删除了v2变量并将其替换为closure2.v2.所以最后一行代码现在需要阅读
var v3 = closure1.v1 + closure2.v2;
然而,要在代码中实际获得此效果,需要EE更改实际上是ENC操作的最后一行代码.虽然这个具体的例子是可能的,但很多场景都不是.
更糟糕的是执行lambda表达式不应该创建一个新的闭包.它实际上应该是将数据附加到原始闭包.此时,您将直接进入限制ENC.
不幸的是,我的小例子只是触及了我们遇到的问题的表面.我一直在说我会写一篇关于这个主题的完整博客文章,希望我本周末有时间.
Lambda表达式,如匿名方法,实际上是非常复杂的野兽.即使我们排除Expression
(.NET 3.5),仍然会留下很多复杂性,尤其是被捕获的变量,从根本上重新构造使用它们的代码(你认为变量成为编译器生成的类的字段)带着一点烟雾和镜子.
因此,我并不会感到惊讶,你不能无所事事地使用它们 - 有很多编译工作(和幕后的类型生成)支持这种魔力.
您不能在立即或监视窗口中使用lambda表达式.
但是,您可以使用System.Linq.Dynamic表达式,其形式为.Where("Id = @ 0",2) - 它没有标准Linq中可用的全部方法,并且没有完整的lambda表达式的力量,但是,它总比没有好!
未来来了!
Visual Studio 2015中添加了对调试lambda表达式的支持(在撰写本文时为预览版).
必须重写Expression Evaluator,因此缺少许多功能:远程调试ASP.NET,在立即窗口中声明变量,检查动态变量等.目前还不支持需要调用本机函数的lambda表达式.
这可能会有所帮助:Visual Studio的扩展立即窗口(在调试中使用Linq,Lambda Expr)
http://extendedimmediatewin.codeplex.com/
http://dvuyka.spaces.live.com/blog/cns!305B02907E9BE19A!381.entry
一切顺利,帕特里克