在 Visual Studio 中调试时,我可以在返回之前找出返回值吗?
Posted
技术标签:
【中文标题】在 Visual Studio 中调试时,我可以在返回之前找出返回值吗?【英文标题】:Can I find out the return value before returning while debugging in Visual Studio? 【发布时间】:2010-09-21 01:10:53 【问题描述】:取如下函数:
DataTable go()
return someTableAdapter.getSomeData();
当我在这个函数中设置断点时,是否有可能检查返回值? go()
直接耦合到 .aspx
页面中的数据网格。
检查返回的数据表的唯一方法是使用临时变量。但是,这有点不方便。没有别的办法吗?
【问题讨论】:
如果你在调用堆栈上移回,你可以添加一个手表 你以前可以在VB6中做到这一点,我似乎记得。但当时函数的语法涉及将函数的值设置为返回值...... Visual C++ 用户的注释:在即时窗口或监视窗口中键入 $ReturnValue。至少在我的 VS 2010 上它有效! 对于 VS2015 使用 $ReturnValue1 .. 以防您不想阅读下面的 20 个答案和 100 个 cmets! 2019 年的答案是什么?这些答案已经过时了。 【参考方案1】:我不知道。请注意,如果您添加变量,编译器无论如何都会在发布版本中删除它...
更新:
This functionality has been added to VS2013。
您可以在自动窗口中查看返回值或在监视/立即窗口中使用$ReturnValue
。
该值只能在从函数返回后直接看到,因此访问它的最简单方法是在函数调用上放置一个断点并跳过 (F10) 调用。
VS2015 更新:嘘!不幸的是,它似乎不在 VS2015 (devenv v14) 中 VS2017 更新:它回来了。 (devenv v15)
【讨论】:
放弃 temp 的原因是可读性和风格,而不是效率,不是吗? @orip 有多种理由不修改代码,例如;这不是您的代码,它是一次性调试,再次单步执行需要很长时间。 (这就是为什么我还是查了这个问题:-) 从 VS 2010 开始可以使用 IntelliTrace:blogs.msdn.com/b/habibh/archive/2009/10/23/… @MarcGravell 你的答案是错误!当然,从您的回复到 MS 在 VS13 中发布该功能,我花了六年时间,但仍然如此。如果您只是添加“暂时”作为免责声明...(不,我没有智障。这是当然是个玩笑。你真神啊,伙计。) @MarcGravell for VS2015:$ReturnValue1 有效! (在最终版本中测试)【参考方案2】:这可以在 Visual Studio 2013 中使用 CLR 4.5.1 according to the customer feedback site 完成。它在 C# 的早期版本中不可用。
(Visual Studio 2008 及更早版本支持 VB.NET。它一直可供 C/C++ 开发人员使用。)
【讨论】:
如何在 Visual Studio 2010 C++ 中做到这一点? Microsoft Connect 表示托管代码存在一个根本问题,无法以可靠的方式实现这一点: @DanSolovay 他们使用的词是“我们无法始终如一地做正确的事情”(对于 VS11),但他们“想要把它带回来”并且“正在寻找一些潜在的解决方案来解决这个问题问题”。 连接条目已过时。该功能似乎被...放弃了:((( 从 VS 2010 开始可以使用 IntelliTrace:blogs.msdn.com/b/habibh/archive/2009/10/23/…【参考方案3】:我同意这是一个非常有用的东西:不仅可以在退出之前查看方法的返回值,还可以查看我刚刚跨过的方法的返回值。我将它作为 Visual Studio 商业扩展的一部分实现,称为“OzCode”。
有了它,您可以直接在代码编辑器上查看方法返回值,就像 HUD 显示一样:
更多信息请见this video。
【讨论】:
看起来不错,但是对于私人用户来说,每年 100 美元的 Visual Studio Extension 实在是太贵了。对于公司而言,情况可能会有所不同。【参考方案4】:根据 Microsoft 的说法,无法使用托管代码可靠地实现这一点。这是他们已经意识到并正在努力解决的问题:
对于那些有调试原生 C++ 或 VB6 代码经验的人,您可能已经使用了在“自动”窗口中为您提供函数返回值的功能。不幸的是,托管代码不存在此功能。虽然您可以通过将返回值分配给局部变量来解决此问题,但这并不方便,因为它需要修改您的代码。 在托管代码中,确定您已跨过的函数的返回值要复杂得多。我们意识到我们无法在这里始终如一地做正确的事情,因此我们删除了该功能,而不是在调试器中为您提供不正确的结果。但是,我们希望为您带来这一点,我们的 CLR 和调试器团队正在寻找一些潜在的解决方案来解决这个问题。不幸的是,这不会成为 Visual Studio 11 的一部分。
https://connect.microsoft.com/VisualStudio/feedback/details/597933/add-a-return-pseudo-variable-to-the-visual-studio-debugger-for-net-code
【讨论】:
根据上述@Alex (***.com/a/3714884/402949),这适用于带有 CLR 4.5 的 VS2013【参考方案5】:关于 Visual Studio 2015:
根据 Marc Gravell 当前接受的答案:
这个functionality has been added to Visual Studio 2013。你可以看到回报 自动窗口中的值或在手表/立即使用 $ReturnValue 窗口
该答案还表明此功能在 Visual Studio 2015 中不起作用。这不是(完全)正确的。在 Examine return values of method calls 上有以下注释:
您必须启用旧版表达式求值器才能识别 $ReturnValue(工具/选项/调试/使用旧版 C# 和 VB 表达式求值器)。否则,您可以使用 $ReturnValue1。
我在 Visual Studio 2015 Enterprise 中对此进行了测试:
关闭旧版表达式评估器:仅 $ReturnValue1 有效 启用旧版表达式评估器:两者 $ReturnValue 和 $ReturnValue1 都有效【讨论】:
这似乎不再是必要的。在 VS 2015 Update 3 上,我禁用了旧版评估器,$ReturnValue
有效。但是,如果您启用了Use managed compatibility mode
调试选项,则返回值不会出现在任何地方。【参考方案6】:
如果您进入菜单Tools → Options,IntelliTrace,并更改设置以收集事件和呼叫信息。
可以回到之前的调用事件(Ctrl + Shift + F11)查看方法调用返回的临时值在 autos 窗口中作为方法名称的子项。
这并不是向您显示您所在方法的返回值。它只是向您显示当前方法中调用的最后一个方法的返回值。
这样就好了
DataTable go()return someTableAdapter.getSomeData();
因为它显示了someTableAdapter.getSomeData()
的返回值。
但不适用于:
int go()return 100 * 99;
【讨论】:
【参考方案7】:.NET 之前的旧技巧:打开 Registers 窗口并查看 EAX 寄存器的值。这包含最后调用的函数的返回值。
【讨论】:
+1 用于更接近金属方法的老派 - 但是,这不适用于所有返回值(显然,这取决于 JIT'er - 谁知道它可能会决定什么疯狂的优化不会使用EAX?)。对于整数类型,它将(大部分?)工作。大值类型是另一回事(据我记得一些博客文章,这些也不会在 VS2013 中显示)。【参考方案8】:使用 Shift-F11 退出 go() 方法,然后在“Autos”调试窗口中将显示刚刚从堆栈中弹出的方法调用的返回值(在本例中为 go()方法,这是你想要的)。这是 Visual Studio 2005 中的行为;我没有使用过 Visual Studio 2008,所以我不知道它在那个版本中的行为是否相同。
【讨论】:
我在 VS2005 和 VS2008 中都试过这个,但我并没有真正看到。我打开了“自动”窗口,但是在“开始”功能中,自动窗口只是空的。同样在退出函数时(函数的右花括号是黄色的)。你能再给我一个提示吗? 我希望 Autos 窗口在 go() 函数内部时为空。您需要完全退出函数(即调试光标应该指向调用 go() 的函数),然后您应该在 Autos 窗口中看到 go() 的返回值。 @LeopardSkinPillBoxHat:即使有您的额外提示,也无法使其正常工作。你在 Visual Basic 中尝试这个吗?它似乎对观察和改变返回值有更好的支持...... @romkyns - “汽车”窗口中为您显示了什么?它不是显示一行指示最后调用的函数返回的内容吗? @LeopardSkinPillBoxHat:不,它在 C# 中没有这样做。附言哇,我花了一段时间才再次看到这个。【参考方案9】:是的,有一个非常好的方法。一个重要的缺点是您必须等待 5 年,甚至 6 年。既然我看到你在 2008 年 11 月发帖,我建议你 waaaaaa...
...啊啊啊。瞧!专为您服务,MS 发布了最新的 Visual Studio 2013,它是在调试模式(菜单 Debug → Windows → 自动)。
【讨论】:
@Doug 因为这个问题是在 2008 年 11 月提出的,而我的回复是在 2014 年 9 月。原始发帖人可能很满意,不想移动信用。但我确实同意你的看法——我不介意我的回答再多些麻烦。我喜欢 upsies 和代表增益。 :) 今天遇到了这个问题。感谢您在 2014 年的回复,即使最初的问题是 2008 年的。您的答案正是我想要的。 @A.P.没问题。看到这个帖子感觉有点像时光机。过去的爆炸,嘿嘿。【参考方案10】:有很多变通方法,但似乎没有一个令人满意。
引用下面的 John Skeet(评论现已删除的答案):
对我来说仍然看起来不方便 - 特别是如果你不知道哪个 您将需要的返回值 在开始调试之前。我真的 不想有一个临时的 变量把我的代码弄得乱七八糟 时间我会返回任何东西。t
理论上,调试器可以有一个return
-变量。毕竟:它只是堆栈上的一个变量:
unsafe
int * sp = stackalloc int[1];
try
return a+b;
finally
Trace.WriteLine("return is " + *(sp+3));
因此,请考虑这是 Visual Studio 的功能请求。
【讨论】:
变量(定义明确的局部变量)和堆栈上的值之间存在很大差异。它是堆栈上的一个值,但它不是一个变量 (=local)。 @Marc:我不确定 CLR 是如何工作的,但是很多编译器将函数参数放在堆栈指针 (sp) 下方的堆栈中,并将局部变量放在堆栈上方的堆栈中指针。这正是我想要展示的。好吧,当返回值是引用类型时,你只是得到一些指针值。 不一定在栈上。事实上,如果你查看 Debug -> Registers 你很容易在 EAX 中看到它【参考方案11】:我想扩展 PascalK's answer 以使其在 Visual Studio 2015 中工作,因为有一个隐藏功能未在 Examine return values of method calls 中记录。
如果您有嵌套函数调用,则会自动创建伪变量$ResultValueX
,其中X 表示函数调用顺序。所以如果有Multiply(Five(), Six())
之类的调用,就会创建以下伪变量:
Five() | $ResultValue1 = 5
Six() | $ResultValue2 = 6
Multiply() | $ResultValue3 = 30
【讨论】:
【参考方案12】:Microsoft Visual C++ 曾经这样做,但 Visual Studio 没有 AFAIK.. :(
【讨论】:
【参考方案13】:我知道的唯一方法是在返回行下一个断点,然后调用快速观察窗口并输入返回的表达式:
someTableAdapter.getSomeData();
但这只有在调用不改变任何对象的状态时才有效(因为当您恢复执行时,会再次调用相同的方法)。
【讨论】:
这也仅在您的表达式没有 lambdas 时才有效。【参考方案14】:你也可以要求评估中间窗口中的值,如果它没有设置标志或其他变量,而只是返回一些东西。
【讨论】:
您需要在问题中包含 lambda,因为我有时也使用即时窗口【参考方案15】:我认为您可以通过查看寄存器窗口(调试/Windows/寄存器)中的 RAX 寄存器来确定这一点。退出函数(SHIFT + F11)后,检查RAX寄存器。我不知道事实,但有一次你可以检查一个寄存器(.NET 之前的日子)并在那里查看返回值。它甚至可能是 RAX 和 RBX 等的组合。
【讨论】:
【参考方案16】:打开 Debug → Autos 窗口会让您关闭。它不会显示实际的返回值,但会显示在 return 语句中评估的内容。
【讨论】:
无法让 VS2008 自动窗口显示类似的内容。你能澄清一下吗?return x + y;
我的意思是如果你在这一行设置一个断点,那么你的Debug-Autos 窗口将显示x 和y 的当前值。正如我所说,它只会让你靠近。只是想提供帮助。我认为这不值得投反对票。【参考方案17】:
是的,通过切换到 VB.NET。 ;P(你刚才说的是“Visual Studio”。;)
只要我记得(从 Visual Basic 到 VB.NET 的所有版本),您就可以简单地查询函数名称。它像在函数开始时隐式声明的局部变量一样“起作用”,并且每当函数通过非返回语句方式退出时(即Exit Function
或刚刚失败),它的当前值也用作返回值,并且当然,当使用 return 语句时。
它也被设置为返回语句的表达式。就像局部变量一样,它的值可以在函数内部的任何执行点检查(包括在执行 return 语句之后)。 C# 没有这个,应该。
VB.NET 的那个小功能(加上它启用的 Exit Function
语句 - C# 不具备且应该具备的另一个功能)在 defensive programming 的形式中非常有用,我经常将函数名初始化为失败/默认值作为第一条语句。然后,在任何失败点(通常比成功点更频繁地发生),我可以简单地调用Exit Function
语句(即无需复制失败/默认表达式甚至常量/变量名称)。
【讨论】:
【参考方案18】:The accepted answer 在 Visual Studio 2015 中无法正常工作,但通过在方法的最后一行放置断点并按 F10,它会将返回值的所有表达式放入当地人窗口。
【讨论】:
【参考方案19】:您可以尝试选择"someTableAdapter.getSomeData();"
,右键单击它,然后选择快速观看。
【讨论】:
【参考方案20】:将返回表达式拖放到监视窗口中。
例如在语句中
return someTableAdapter.getSomeData();
拖放
someTableAdapter.getSomeData()
进入监视窗口,您将看到值。
您可以对任何表达式执行此操作。
【讨论】:
问题在于:表达式被计算了两次。 而且 watch 表达式不能包含 lambda 表达式,我用的比较多。【参考方案21】:在 VS2019 中,只需转到 Debug->Windows->Autos 窗口。在那里,您会看到如下所示的 concat 返回值:
【讨论】:
以上是关于在 Visual Studio 中调试时,我可以在返回之前找出返回值吗?的主要内容,如果未能解决你的问题,请参考以下文章
在 Visual Studio 中调试时,我可以将一些 C/C++ 结构内容保存到磁盘吗?
非调试模式时在 Visual Studio 的输出窗口中显示消息?
非调试模式时在 Visual Studio 的输出窗口中显示消息?
在 Visual Studio 2012 中调试 C++ 代码时跳过 STL 代码?