为什么在“快速监视”窗口中调试时不能使用lambda表达式?
UPD:另请参见
http://blogs.msdn.com/b/jaredpar/archive/2009/08/26/why-no-linq-in-debugger-windows.aspx
为什么在“快速监视”窗口中调试时不能使用lambda表达式?
UPD:另请参见
http://blogs.msdn.com/b/jaredpar/archive/2009/08/26/why-no-linq-in-debugger-windows.aspx
Answers:
Lambda表达式就像匿名方法一样,实际上是非常复杂的野兽。即使我们排除Expression
(.NET 3.5),仍然还有很多复杂性,尤其是捕获的变量,这些变量从根本上重新构造了使用它们的代码(您认为变量成为编译器生成的类中的字段) ,有一点烟雾和镜子。
因此,您可以无所事事地使用它们,我一点也不感到惊讶-有很多支持这种魔术的编译器工作(以及幕后的类型生成)。
不,您不能在watch / locals /即时窗口中使用lambda表达式。正如Marc所指出的那样,这非常复杂。不过,我想进一步探讨这个话题。
大多数人在调试器中执行匿名函数时不会考虑的是,它不会在真空中发生。定义和运行匿名函数的行为改变了代码库的基础结构。通常,尤其是从即时窗口更改代码是一项非常困难的任务。
考虑下面的代码。
void Example() {
var v1 = 42;
var v2 = 56;
Func<int> func1 = () => v1;
System.Diagnostics.Debugger.Break();
var v3 = v1 + v2;
}
此特定代码创建一个单个闭包以捕获值v1。每当匿名函数使用在其作用域之外声明的变量时,都需要捕获闭包。出于所有意图和目的,此功能中不再存在v1。最后一行实际上更像以下内容
var v3 = closure1.v1 + v2;
如果在调试器中运行了Example函数,它将在Break行停止。现在,假设用户是否在监视窗口中输入了以下内容
(Func<int>)(() => v2);
为了正确执行此操作,调试器(或更合适的EE)将需要为变量v2创建一个闭包。这很难但并非不可能。
对于EE而言,真正使这项工作变得艰难的是最后一行。现在应该如何执行该行?出于所有目的和目的,匿名函数删除了v2变量,并将其替换为closure2.v2。所以现在实际上需要阅读最后一行代码
var v3 = closure1.v1 + closure2.v2;
然而,要在代码中实际获得这种效果,则EE必须更改最后一行代码,这实际上是ENC动作。尽管可以使用此特定示例,但大部分情况都不可行。
更糟糕的是执行lambda表达式不应创建新的闭包。它实际上应该将数据附加到原始闭包中。此时,您会直接遇到ENC的限制。
不幸的是,我的小例子只能解决我们遇到的问题。我一直说我会写一篇完整的博客文章,希望这个周末有时间。
您不能在“即时”或“监视”窗口中使用lambda表达式。
但是,您可以使用System.Linq.Dynamic表达式,其形式为.Where(“ Id = @ 0”,2)-它没有标准Linq中可用的全部方法,也没有完整的方法Lambda表达式的强大功能,但总比没有好!
.Any(string predicate)
,您也可以.Where("Id>2").Any()
在“监视窗口”或“固定到源代码”中添加类似内容。这很棒!
未来来了!
对调试lambda表达式的支持已添加到Visual Studio 2015(在撰写本文时为预览)。
Expression Evaluator必须重写,因此缺少许多功能:远程调试ASP.NET,在Instant窗口中声明变量,检查动态变量等。目前还不支持需要调用本机函数的lambda表达式。
这可能会有所帮助:Visual Studio的扩展即时窗口(在调试中使用Linq,Lambda Expr)
一切顺利,帕特里克
调试器的表达式评估器不支持Lambda表达式...这不足为奇,因为在编译时,它们用于创建方法(或表达式树)而不是表达式(在Reflector中将显示切换到.NET 2来查看)。看他们)。
加上它们当然可以形成封闭结构,这是另一层完整的结构。
Expression
树-这取决于上下文。
在VS 2015中,您现在可以这样做,这是他们添加的新功能之一。
如果仍然需要使用Visual Studio 2013,则实际上也可以使用包管理器控制台窗口在立即窗口中编写循环或lambda表达式。就我而言,我在函数顶部添加了一个列表:
private void RemoveRoleHierarchy()
{
#if DEBUG
var departments = _unitOfWork.DepartmentRepository.GetAll().ToList();
var roleHierarchies = _unitOfWork.RoleHierarchyRepository.GetAll().ToList();
#endif
try
{
//RoleHierarchy
foreach (SchoolBo.RoleHierarchy item in _listSoRoleHierarchy.Where(r => r.BusinessKeyMatched == false))
_unitOfWork.RoleHierarchyRepository.Remove(item.Id);
_unitOfWork.Save();
}
catch (Exception e)
{
Debug.WriteLine(e.ToString());
throw;
}
}
我的GetAll()
职能是:
private DbSet<T> _dbSet;
public virtual IList<T> GetAll()
{
List<T> list;
IQueryable<T> dbQuery = _dbSet;
list = dbQuery
.ToList<T>();
return list;
}
在这里,我一直收到以下错误,因此我想打印出各个存储库中的所有项目:
InnerException {“ DELETE语句与REFERENCE约束\” FK_dbo.Department_dbo.RoleHierarchy_OranizationalRoleId \“发生冲突。冲突发生在数据库\” CC_Portal_SchoolObjectModel \“,表\” dbo.Department \“,列'OranizationalRoleId'中。\ r \ nThen语句已终止。“} System.Exception {System.Data.SqlClient.SqlException}
然后,通过在立即窗口中执行以下操作,找出部门存储库中有多少条记录:
_unitOfWork.DepartmentRepository.GetAll().ToList().Count
其中返回243。
因此,如果在包管理器控制台中执行以下命令,它将打印出所有项目:
PM> for($i = 0; $i -lt 243; $i++) { $a = $dte.Debugger.GetExpression("departments[$i].OrgagnizationalRoleId"); Write-Host $a.Value $i }
这个想法的作者可以在这里找到
要回答您的问题,这是Visual Studio程序管理器对为什么您不能执行此操作的正式解释。简而言之,因为在VS中实现“确实非常非常困难”。但是该功能目前正在开发中(2014年8月更新)。
在那里添加您的投票!