C# Visual Studio 调试“快速观察”工具和 lambda 表达式

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/725499/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 22:39:48  来源:igfitidea点击:

Visual Studio debugging "quick watch" tool and lambda expressions

c#visual-studiodebugginglambda

采纳答案by Marc Gravell

Lambda expressions, like anonymous methods, are actually very complex beasts. Even if we rule out Expression(.NET 3.5), that still leaves a lotof 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.

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

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

因此,我一点也不惊讶您不能随意使用它们 - 有很多编译器工作(以及幕后的类型生成)支持这种魔法。

回答by Richard

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).

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

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

此外,它们当然可以形成一个封闭,另一个完整的结构层。

回答by JaredPar

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.

不,您不能在 watch/locals/immediate 窗口中使用 lambda 表达式。正如 Marc 所指出的,这非常复杂。不过,我想更深入地探讨这个话题。

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 defining 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

这个特定的代码创建了一个闭包来捕获值 v1。每当匿名函数使用在其作用域外声明的变量时,都需要闭包捕获。出于所有意图和目的,此函数中不再存在 v1。最后一行实际上看起来更像下面这样

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

如果函数 Example 在调试器中运行,它将在 Break 行停止。现在想象一下,如果用户在监视窗口中键入以下内容

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

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

为了正确执行这个调试器(或更合适的 EE)需要为变量 v2 创建一个闭包。这很难,但并非不可能做到。

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

对 EE 来说,真正使这成为一项艰巨工作的是最后一行。现在应该如何执行该行?出于所有意图和目的,匿名函数删除了 v2 变量并将其替换为closure2.v2。所以最后一行代码现在真的需要阅读

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.

然而,要在代码中真正获得这种效果,需要 EE 更改实际上是 ENC 操作的最后一行代码。虽然这个特定的例子是可能的,但大部分场景不是。

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.

更糟糕的是执行 lambda 表达式不应该创建一个新的闭包。它实际上应该将数据附加到原始闭包中。此时,您将直接进入 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.

不幸的是,我的小例子只触及了我们遇到的问题的表面。我一直说我会写一篇关于这个主题的完整博客文章,希望这个周末我有时间。

回答by Patrick Wolf

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

这可能会有所帮助:Visual Studio 的扩展即时窗口(在调试中使用 Linq、Lambda Expr)

All the best, Patrick

祝一切顺利,帕特里克

回答by stusherwin

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

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

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!

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

回答by Francisco d'Anconia

To answer your question, here's the Visual Studio Program Manager's official explanation of why you can't do this. In short, because "it's really, really hard" to implement in VS. But the feature is currently in progress (as updated on Aug 2014).

为了回答您的问题,这里是 Visual Studio 程序管理器关于为什么不能这样做的官方解释。简而言之,因为在 VS 中实现“真的非常非常困难”。但该功能目前正在进行中(如 2014 年 8 月更新)。

Allow the evaluation of lambda expressions while debugging

允许在调试时评估 lambda 表达式

Add your vote while you're there!

当你在那里时添加你的投票!

回答by Athari

The future has come!

未来已来!

Support for debugging lambda expressions has been added to Visual Studio 2015(Previewat the time of writing).

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

Expression Evaluator had to be rewritten, so many features are missing: remote debugging ASP.NET, declaring variables in Immediate window, inspecting dynamic variables etc. Also lambda expressions that require calls to native functions aren't currently supported.

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

回答by user8128167

If you still need to use Visual Studio 2013, you can actually write a loop, or lambda expression in the immediate window using also the package manager console window. In my case, I added a list at the top of the function:

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

Where my GetAll()function is:

我的GetAll()功能在哪里:

private DbSet<T> _dbSet;

public virtual IList<T> GetAll()
{
    List<T> list;
    IQueryable<T> dbQuery = _dbSet;
    list = dbQuery
        .ToList<T>();

    return list;
}

Here I kept getting the following error, so I wanted to print out all the items in the various repositories:

在这里我不断收到以下错误,所以我想打印出各种存储库中的所有项目:

InnerException {"The DELETE statement conflicted with the REFERENCE constraint \"FK_dbo.Department_dbo.RoleHierarchy_OranizationalRoleId\". The conflict occurred in database \"CC_Portal_SchoolObjectModel\", table \"dbo.Department\", column 'OranizationalRoleId'.\r\nThe statement has been terminated."} System.Exception {System.Data.SqlClient.SqlException}

InnerException {"DELETE 语句与 REFERENCE 约束 \"FK_dbo.Department_dbo.RoleHierarchy_OranizationalRoleId\" 发生冲突。冲突发生在数据库 \"CC_Portal_SchoolObjectModel\",表 \"dbo.Department\",列 'OranizationalRoleId'。\r\n语句已终止。”} System.Exception {System.Data.SqlClient.SqlException}

Then, I find out how many records are in the department repository by executing this in the immediate window:

然后,我通过在即时窗口中执行此命令来找出部门存储库中有多少记录:

_unitOfWork.DepartmentRepository.GetAll().ToList().Count

Which returned 243.

其中返回 243。

So, if you execute the following in the package manager console, it prints out all the items:

因此,如果您在包管理器控制台中执行以下操作,它会打印出所有项目:

PM> for($i = 0; $i -lt 243; $i++) { $a = $dte.Debugger.GetExpression("departments[$i].OrgagnizationalRoleId"); Write-Host $a.Value $i }

The author for the idea can be found here

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

回答by loneshark99

In VS 2015 you can do so now,this is one of the new feature they added.

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