我可以在Visual Studio中进行调试时在返回之前找出返回值吗?


387

具有以下功能:

DataTable go() {
    return someTableAdapter.getSomeData();
}

当我在此函数中设置断点时,是否有可能检查返回的值?go()直接耦合到.aspx页面中的数据网格。

检查返回的数据表的唯一方法是使用临时变量。但是,这有点不方便。有没有其他办法?


1
如果您移回呼叫堆栈,则可以添加手表
Chris S

我似乎记得您曾经在VB6中能够做到这一点。但是,那时函数的语法涉及将函数的值设置为返回值……
Neil Barnwell 2010年

5
对于Visual C ++用户的注释:在“立即”窗口或“监视”窗口中键入$ ReturnValue。至少在我的VS 2010上有效!
sergiol 2013年

9
对于VS2015,请使用$ ReturnValue1 ..如果您不想通读下面的20个答案和100条注释!
felickz '16

3
这一切的2019年答案是什么?这些答案是过时的。
dylanh724 '19

Answers:


264

从来没听说过。请注意,如果您确实添加了一个变量,则无论如何它都会在发行版中被编译器删除...

更新: 此功能已添加到VS2013中。您可以在自动窗口中查看返回值,也可以$ReturnValue在监视/立即窗口中使用返回值。

仅在从函数返回后才能直接看到该值,因此访问它的最简单方法是在函数调用上放置一个断点并跳过(F10)调用。


VS2015更新:嘘!不幸的是,它似乎不在VS2015的VS2015(devenv v14)
更新中:它回来了。(devenv v15)


12
放弃临时工作的原因是可读性和风格,而不是效率,不是吗?
orip

8
这是可能的,因为在VS 2010中使用IntelliTrace:blogs.msdn.com/b/habibh/archive/2009/10/23/...
丹尼尔Hilgarth

2
Intellitrace仅在VS Ultimate Edition中可用。
JMGH 2014年

3
@MarcGravell您的回答是错误的!当然,从您的答复到MS在VS13中发布该功能之间,我花了六年的时间,但仍然如此。如果您暂时只添加“ ”作为免责声明...(不,我没有弱智。当然,这个玩笑。您真是
太棒了

6
VS2015的@MarcGravell:$ ReturnValue1有效!(经过最终版本测试)
GY16年

58

根据客户反馈网站,这可以在带有CLR 4.5.1的Visual Studio 2013中完成。在C#的早期版本中不可用。

(Visual Studio 2008和更早版本的VB.NET支持它。C/ C ++开发人员一直可以使用。)


1
如何在Visual Studio 2010 C ++中做到这一点?
用户

Microsoft Connect说托管代码存在一个基本问题,导致无法以可靠的方式实现此目标:
Dan Solovay 2012年

@DanSolovay他们使用的词是“我们不能始终如一地做正确的事情”(对于VS11),但是他们“想把它带回来”,并且“正在寻找解决这个问题的许多潜在解决方案”。
亚历克斯·安加斯

连接条目已过期。该功能似乎已被放弃...(:((
Softlion 2012年

1
这是可能的,因为在VS 2010中使用IntelliTrace:blogs.msdn.com/b/habibh/archive/2009/10/23/...
丹尼尔Hilgarth

25

我同意这是非常有用的事情:不仅在退出方法之前先查看方法的返回值,而且还要查看我刚执行的方法的返回值。我将其实现为Visual Studio商业扩展的一部分,该扩展称为“ OzCode ”。

使用它,您可以在代码编辑器上以HUD显示的形式查看方法返回值:

语句可视化

有关更多信息,请参见此视频


23

根据Microsoft的说法,无法使用托管代码可靠地实现此目的。这是他们意识到并正在解决的问题:

对于那些有调试本机C ++或VB6代码经验的人,您可能使用了在“自动”窗口中为您提供函数返回值的功能。不幸的是,托管代码不存在此功能。尽管您可以通过将返回值分配给局部变量来解决此问题,但这并不方便,因为它需要修改您的代码。在托管代码中,确定您跨过的函数的返回值要麻烦得多。我们意识到在这里无法始终如一地做正确的事情,因此我们删除了该功能,而不是在调试器中给您错误的结果。但是,我们希望为您带来帮助,我们的CLR和Debugger团队正在寻找解决此问题的许多潜在解决方案。不幸的是,这将不属于Visual Studio 11。

https://connect.microsoft.com/VisualStudio/feedback/details/597933/add-a-return-pseudo-variable-to-the-visual-studio-debugger-for-net-code


1
根据上述@Alex (stackoverflow.com/a/3714884/402949),此功能可用于带有CLR 4.5的VS2013
Dan Solovay

21

关于Visual Studio 2015:

根据Marc Gravell当前接受的答案:

功能已添加到Visual Studio 2013中。您可以在汽车窗口中查看返回值,也可以在监视/立即窗口中使用$ ReturnValue

该答案还表明,此功能在Visual Studio 2015中不起作用。(并非完全如此)这不是事实。在检查方法调用的返回值时,有以下注意事项:

您必须打开旧式表达式评估器才能识别$ ReturnValue (工具/选项/调试/使用旧式C#和VB表达式评估器)。否则,您可以使用$ ReturnValue1

我在Visual Studio 2015 Enterprise中对此进行了测试:

  • 关闭旧式表达式评估器: $ ReturnValue1有效
  • 与传统表达评价者打开: $返回值 $ ReturnValue1工作

3
这似乎不再是必需的。在VS 2015 Update 3上,我禁用了旧版评估程序并且$ReturnValue可以工作。但是,如果Use managed compatibility mode启用了调试选项,则返回值不会出现在任何地方。
尼克

13

如果转到菜单工具选项,IntelliTrace,然后更改设置以收集事件和呼叫信息。

您可以返回到上一个调用事件(Ctrl+ Shift+ F11),并在autos窗口中查看从方法调用返回的临时值,作为方法名称的子代。

这并没有显示您所使用方法的返回值。它只是显示了当前方法中调用的最后一个方法的返回值。

所以,这对

DataTable go(){return someTableAdapter.getSomeData();}

因为它显示了的返回值someTableAdapter.getSomeData()

但不适用于:

int go(){return 100 * 99;}

12

.NET以前的古老技巧:打开“寄存器”窗口,查看EAX寄存器的值。它包含最后一个调用函数的返回值。


1
+1对于更接近于金属方法的老派而言-但这对所有返回值都无效(显然,这取决于JIT'er-谁知道它可能决定采用哪种疯狂的优化而不使用EAX? )。对于整数类型,它将(通常是?)起作用。大值类型是另一回事(据我从某些博客文章中回忆,那些值也不会在VS2013中显示)。
JimmiTh

10

使用Shift-F11退出go()方法,然后在“自动”调试窗口中显示刚刚从堆栈弹出的方法调用的返回值(在这种情况下,go()方法为你想要什么)。这是Visual Studio 2005中的行为。我没有使用过Visual Studio 2008,所以我不知道它在该版本中的行为是否相同。


我已经在VS2005和VS2008中都尝试过了,但是我并没有真正看到它。我打开了“自动”窗口,但是在“执行”功能中,自动窗口是空的。同样,退出该功能时(该功能的右花括号为黄色)。你能再给我一个提示吗?
doekman

我希望在go()函数内部时Autos窗口为空。您需要完全执行该函数(即调试光标应指向具有CALLED go()的函数),然后您应该在Autos窗口中看到go()的返回值。
LeopardSkinPillBoxHat

@LeopardSkinPillBoxHat:即使有额外提示,也无法正常工作。您正在Visual Basic中尝试吗?它似乎对观察和更改返回值具有更好的支持...
Roman Starkov 09年

@romkyns-在“自动”窗口中会为您显示什么?它不显示一行指示最后调用的函数返回了什么吗?
LeopardSkinPillBoxHat

2
@LeopardSkinPillBoxHat:不,在C#中不这样做。PS Wow,花了我一段时间再看一遍。
罗曼·斯塔科夫

7

是的,有一个非常好的方法。一个重大的缺点是您必须等待5到6年。由于我看到您是在2008年11月发布的,因此建议您waaaaaa ...

... aaaait。和瞧!MS仅针对您发布了最新的Visual Studio 2013,它是在调试模式下运行时从菜单中可访问的默认功能(菜单DebugWindowsAutos)。


@Doug因为在2008年11月提出了这个问题,而我的答复是在2014年9月提出的。最初的张贴者可能很满意,并且不想转移任何荣誉。但是,我确实同意您的意见-我不介意我的回答有更多麻烦。我喜欢小礼物和代表收获。:)
Konrad Viltersten

今天有这个问题。即使最初的发行是2008年,也感谢您在2014年的答复。您的答案就是我想要的。
美联社

@AP没问题。感觉有点像一台时光机,看到了这篇文章。爆炸过去,呵呵。
Konrad Viltersten

5

有很多变通办法,但似乎都不令人满意。

在下面引用John Skeet(评论已删除的答案):

仍然给我带来不便-特别是如果您在开始调试之前不知道需要哪个返回值。我真的不想每次我返回任何东西时都必须有一个临时变量使我的代码混乱。

从理论上讲,调试器可以具有return-variable。毕竟:这只是堆栈上的一个变量:

unsafe {
  int * sp = stackalloc int[1];
  try {
    return a+b;
  }
  finally {
    Trace.WriteLine("return is " + *(sp+3));
  }
}

因此,请考虑将其作为Visual Studio的功能请求。


变量(定义良好的局部变量)和堆栈上的值之间有很大的不同。它是堆栈上的一个值,但不是变量(= local)。
Marc Gravell

@Marc:我不确定CLR的工作方式,但是许多编译器将函数参数放在堆栈指针(sp)下方的堆栈上,并将局部变量放在堆栈指针上方的堆栈上。这就是我要显示的。好的,当返回值是引用类型时,您只需获取一些指针值。
doekman 2011年

1
它不一定在堆栈上。事实上,如果你查看调试- >寄存器你容易看到它在EAX
马克Sowul

5

我想扩展PascalK的答案,以使其在Visual Studio 2015中工作,因为有一个隐藏的功能未在“ 检查方法调用的返回值”中进行记录

如果您具有嵌套的函数调用,$ResultValueX则会自动创建伪变量,其中X表示函数调用顺序。因此,如果您有诸如这样的调用Multiply(Five(), Six()),则会创建以下伪变量:

Five()     | $ResultValue1 = 5
Six()      | $ResultValue2 = 6
Multiply() | $ResultValue3 = 30

2

Microsoft Visual C ++曾经这样做,但是Visual Studio并不AFAIK .. :(


2

我知道的唯一方法是在返回行上放置一个断点,然后调用“ 快速监视”窗口并输入返回的表达式:

someTableAdapter.getSomeData();

但这仅在调用不更改任何对象的状态的情况下才有效(因为当您恢复执行时将再次调用同一方法)。


5
这也仅在您的表达式没有lambda时有效。
罗曼·斯塔科夫

1

您也可以要求在中间窗口中评估该值,如果它未设置标志或其他变量,而仅返回某些内容。


您需要在问题中包括lambda,因为我有时也使用即时窗口
Chris S

1

我认为您可以通过在“寄存器”窗口(“调试” /“ Windows” /“寄存器”)中查看RAX寄存器来确定这一点。退出功能(SHIFT + F11)后,检查RAX寄存器。我不知道一个事实,但是一旦过了月亮,您就可以检查一个寄存器(.NET之前的日子)并在那里查看返回值。它甚至可能是RAX和RBX等的组合。


1

打开“调试”→“自动”窗口,即可关闭。它不会显示实际的返回值,但是会显示在return语句中评估的内容。


2
无法使VS2008自动窗口显示类似的内容。你能澄清一下吗?
罗曼·斯塔科夫

return x + y; 我的意思是,如果您在此行上设置断点,则Debug-Autos窗口将显示x和y的当前值。就像我说的,只有你靠近你。只是想有所帮助。我认为这不应该被否决。
GeekyMonkey

1

是的,通过切换到VB.NET。; P(您刚才说的是“ Visual Studio”。)

只要我能记住(从Visual Basic到VB.NET的所有版本),您都可以简单地查询函数名称。它像局部变量一样在函数的“函数”中隐式声明,该变量在函数的开始处隐含声明,并且当函数通过非返回语句(例如,Exit Function或者只是掉进去)退出时(当然,当函数退出时),其当前值也用作返回值。使用return语句。

它还设置为return语句的表达式。就像局部变量一样,可以在函数内部的任何执行点(包括执行return语句之后)检查其值。C#没有,应该。

VB.NET的那个小功能(加上Exit Function它启用的语句-C#没有并且应该有的另一个功能)以防御性编程的形式非常有用,我在实践中始终将函数名称初始化为failure / default值,例如第一个陈述。然后,在任何故障点(通常比成功点发生的频率要高得多),我可以简单地调用该Exit Function语句(即,无需重复故障/默认表达式甚至是常量/变量名称)。




-1

将return表达式拖放到监视窗口中。

例如,在语句中

return someTableAdapter.getSomeData();

拖放

someTableAdapter.getSomeData()

进入观察窗口,您将看到该值。

您可以对任何表达式执行此操作。


2
问题在于:表达式被计算两次。
doekman

6
并且watch表达式不能包含lambda表达式,我使用了一些。
史蒂夫·克兰
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.