Visual Studio调试“快速监视”工具和lambda表达式


96

5
这已完成,可在VS 2015预览中使用。visualstudio.uservoice.com/forums/121579-visual-studio/...
旧金山D'Anconia


我尝试了在MSDN上给出的用于lambda表达的非常简单的示例,但是它不起作用。我拥有VS 2015企业版
2013年

2
@ Franciscod'Anconia要在调试中启用lambda支持,必须选中“使用托管的兼容模式”(stackoverflow.com/a/36559817/818321)结果,您将无法使用条件断点:blogs.msdn .microsoft.com / devops / 2013/10/16 /…stackoverflow.com/a/35983978/818321
Nik

Answers:


64

Lambda表达式就像匿名方法一样,实际上是非常复杂的野兽。即使我们排除Expression(.NET 3.5),仍然还有很多复杂性,尤其是捕获的变量,这些变量从根本上重新构造了使用它们的代码(您认为变量成为编译器生成的类中的字段) ,有一点烟雾和镜子。

因此,您可以无所事事地使用它们,我一点也不感到惊讶-有很多支持这种魔术的编译器工作(以及幕后的类型生成)。


91

不,您不能在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的限制。

不幸的是,我的小例子只能解决我们遇到的问题。我一直说我会写一篇完整的博客文章,希望这个周末有时间。


41
抱怨,抱怨,接受平庸,抱怨,抱怨。调试器是IDE的核心,您将它弄坏了!监视窗口中的Lambda不需要捕获任何内容。像任何其他监视代码一样,它们仅在特定的堆栈帧才有意义。(否则,您将捕获该变量,然后使用相同的变量名移到另一个函数……什么?)调试器的作用是破坏编译器。让它起作用!
Aleksandr Dubinsky 2013年

2
为什么简单,不允许在监视窗口的lambda上捕获变量。很简单,将允许一堆调试场景,其中lambda只是在真正的功能代码中使用。
Luiz Felipe 2014年

@LuizFelipe甚至仍然是一个巨大的挑战。它要求EE实际生成用于回调的完整功能主体(一直到IL)。如今,EE并没有执行任何此类操作,而是充当解释器。
JaredPar

1
@JaredPar您可以分享博客谈论的话题吗
Ehsan Sajjad

49

您不能在“即时”或“监视”窗口中使用lambda表达式。

但是,您可以使用System.Linq.Dynamic表达式,其形式为.Where(“ Id = @ 0”,2)-它没有标准Linq中可用的全部方法,也没有完整的方法Lambda表达式的强大功能,但总比没有好!


2
好吧……虽然其他人在不可能的情况下进行了解释,但这至少为我们提供了一种可能的解决方案。+1
Nullius

1
为了澄清起见,您“导入System.Linq.Dynamic”,然后在调试窗口中输入“” Where(something.AsQueryable,“ property> xyz”,nothing)'
smirkingman 2014年

这很棒。即使您没有完整的Linq Extension方法,例如,没有.Any(string predicate),您也可以.Where("Id>2").Any()在“监视窗口”或“固定到源代码”中添加类似内容。这很棒!
保护者

22

未来来了!

对调试lambda表达式的支持已添加到Visual Studio 2015(在撰写本文时为预览)。

Expression Evaluator必须重写,因此缺少许多功能:远程调试ASP.NET,在Instant窗口中声明变量,检查动态变量等。目前还不支持需要调用本机函数的lambda表达式。


很高兴看到。凉...!
Rahul Nikate



2

调试器的表达式评估器不支持Lambda表达式...这不足为奇,因为在编译时,它们用于创建方法(或表达式树)而不是表达式(在Reflector中将显示切换到.NET 2来查看)。看他们)。

加上它们当然可以形成封闭结构,这是另一层完整的结构。


好吧,他们可能会创建方法。他们可能会创建Expression树-这取决于上下文。
Marc Gravell

1

在VS 2015中,您现在可以这样做,这是他们添加的新功能之一。


1

如果仍然需要使用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 }

这个想法的作者可以在这里找到


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.