ChatGPT解决这个技术问题 Extra ChatGPT

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

采取以下功能:

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

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

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

如果您移回调用堆栈,则可以添加手表
你以前可以在 VB6 中做到这一点,我似乎记得。但当时函数的语法涉及将函数的值设置为返回值......
对 Visual C++ 用户的评论:在即时窗口或监视窗口中键入 $ReturnValue。至少在我的 VS 2010 上它有效!
对于 VS2015,请使用 $ReturnValue1 .. 如果您不想阅读下面的 20 个答案和 100 条评论!
所有这一切的 2019 年答案是什么?这些答案是超级过时的。

A
Apfelkuacha

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

更新: This functionality has been added to VS2013。您可以在自动窗口中查看返回值或在监视/立即窗口中使用 $ReturnValue

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

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


放弃 temp 的原因是可读性和风格,而不是效率,不是吗?
从带有 IntelliTrace 的 VS 2010 开始就有可能:blogs.msdn.com/b/habibh/archive/2009/10/23/…
@MarcGravell 你的答案是错误的!当然,从您的回复到 MS 在 VS13 中发布该功能,我花了六年时间,但仍然如此。如果您只添加“暂时”作为免责声明...(不,我没有智障。当然,这是个玩笑。您真是神一样,伙计。)
@MarcGravell for VS2015: $ReturnValue1 有效! (在终极版中测试)
我会指出,在 VS2019 中(至少),智能感知建议 $returnvalue 全部小写。但是它区分大小写。
P
Peter Mortensen

这可以在带有 CLR 4.5.1 according to the customer feedback site 的 Visual Studio 2013 中完成。它在 C# 的早期版本中不可用。

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


你如何在 Visual Studio 2010 C++ 中做到这一点?
Microsoft Connect 表示,托管代码存在一个基本问题,阻碍了以可靠方式实现这一点:
@DanSolovay 他们使用的词是“我们无法始终如一地做正确的事情”(对于 VS11),但他们“想把它带回来”并且“正在寻找一些潜在的解决方案来解决这个问题”。
连接条目已过时。该功能似乎被...放弃了:(((
从带有 IntelliTrace 的 VS 2010 开始就有可能:blogs.msdn.com/b/habibh/archive/2009/10/23/…
D
Dror Helper

我同意这是一件非常有用的事情:不仅可以在退出之前查看方法的返回值,还可以查看我刚刚跨过的方法的返回值。我将它作为 Visual Studio 商业扩展的一部分实现,称为“OzCode”。

有了它,您可以直接在代码编辑器上查看方法返回值,就像 HUD 显示一样:

https://i.stack.imgur.com/Kw7mp.gif

有关详细信息,请参阅 this video


看起来不错,但是 Visual Studio Extension 每年 100 美元对私人用户来说实在是太多了。对于公司来说,这可能会有所不同。
D
Dan Solovay

根据微软的说法,没有办法通过托管代码可靠地实现这一点。这是他们意识到并正在解决的问题:

对于那些有调试本机 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 (stackoverflow.com/a/3714884/402949),这适用于带有 CLR 4.5 的 VS2013
S
StayOnTarget

关于 Visual Studio 2015:

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

此功能已添加到 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 调试选项,则返回值不会出现在任何地方。
P
Peter Mortensen

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

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

这不会向您显示您所在方法的返回值。它只是向您显示当前方法中调用的最后一个方法的返回值。

所以,这很好

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

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

但不适用于:

int go(){return 100 * 99;}

P
Peter Mortensen

.NET 之前的老技巧:打开 Registers 窗口并查看 EAX 寄存器的值。这包含最后调用的函数的返回值。


+1 对于更接近金属方法的老派 - 但是,这不适用于所有返回值(显然,这取决于 JIT'er - 谁知道它可能会决定哪些疯狂的优化不会使用 EAX? )。对于整数类型,它将(大部分?)工作。大值类型是另一回事(据我记得一些博客文章,这些也不会在 VS2013 中显示)。
L
LeopardSkinPillBoxHat

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


我在 VS2005 和 VS2008 中都试过这个,但我并没有真正看到它。我打开了“自动”窗口,但是在“开始”功能中,自动窗口只是空的。同样在退出函数时(函数的右花括号是黄色的)。你能再给我一个提示吗?
我希望 Autos 窗口在 go() 函数内部时为空。您需要完全退出该函数(即调试光标应该指向调用了 go() 的函数),然后您应该在 Autos 窗口中看到 go() 的返回值。
@LeopardSkinPillBoxHat:即使有您的额外提示,也无法使其正常工作。你在 Visual Basic 中尝试这个吗?它似乎对观察和改变返回值有更好的支持......
@romkyns - “汽车”窗口中为您显示了什么?它不会显示一行指示最后调用的函数返回的内容吗?
@LeopardSkinPillBoxHat:不,它在 C# 中没有这样做。 PS哇,我花了一段时间再次看到这个。
P
Peter Mortensen

是的,有一个非常好的方法。一个重要的缺点是您必须等待 5 年,甚至 6 年。既然我看到你在 2008 年 11 月发帖,我建议你 waaaaaa...

……啊啊啊。瞧!只是为了您,MS 发布了最新的 Visual Studio 2013,它是在调试模式下运行时可从菜单访问的默认功能(菜单调试 → Windows → 自动)。


@Doug 因为这个问题是在 2008 年 11 月提出的,而我的回复是在 2014 年 9 月。原始发帖人可能很满意,不想移动信用。但我确实同意你的看法——我不介意我的回答再多些麻烦。我喜欢 upsies 和代表增益。 :)
今天遇到了这个问题。感谢您在 2014 年的回复,即使最初的问题是 2008 年的。您的答案就是我想要的。
@AP 没问题。看到这个帖子感觉有点像时光机。过去的爆炸,嘿嘿。
P
Peter Mortensen

有很多解决方法,但似乎没有一个令人满意。

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

对我来说仍然看起来很不方便 - 特别是如果您在开始调试之前不知道需要哪个返回值。我真的不想每次我返回任何东西时都需要一个临时变量来弄乱我的代码。t

理论上,调试器可以有一个 return 变量。毕竟:它只是堆栈上的一个变量:

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

因此,请将此视为 Visual Studio 的功能请求。


变量(定义明确的局部变量)和堆栈上的值之间存在很大差异。它是堆栈上的值,但不是变量(=本地)。
@Marc:我不确定 CLR 是如何工作的,但是许多编译器将函数参数放在堆栈指针 (sp) 下方的堆栈中,并将局部变量放在堆栈指针上方的堆栈中。这正是我想要展示的。好的,当返回值是引用类型时,你只会得到一些指针值。
它不一定在堆栈上。事实上,如果你查看 Debug -> Registers 你很容易在 EAX 中看到它
P
Peter Mortensen

我想扩展 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

S
Sprintstar

Microsoft Visual C++ 曾经这样做,但 Visual Studio 没有 AFAIK.. :(


P
Peter Mortensen

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

someTableAdapter.getSomeData();

但这仅在调用未更改任何对象的状态时才有效(因为当您恢复执行时,将对同一方法进行第二次调用)。


这也仅在您的表达式没有 lambda 时才有效。
B
Biri

您也可以要求评估中间窗口中的值,如果它没有设置标志或其他变量,而只是返回一些东西。


您需要在问题中包含 lambda,因为我有时也使用即时窗口
J
Joe Rattz

我认为您可以通过查看 Registers 窗口(Debug / Windows / Registers)中的 RAX 寄存器来确定这一点。退出函数(SHIFT + F11)后,检查RAX寄存器。我不知道事实,但有一次你可以检查一个寄存器(.NET 之前的日子)并在那里查看返回值。它甚至可能是 RAX 和 RBX 等的组合。


P
Peter Mortensen

打开 Debug → Autos 窗口会让你关闭。它不会显示实际的返回值,但会显示在 return 语句中评估的内容。


无法让 VS2008 自动窗口显示类似的内容。你能澄清一下吗?
return x + y; 我的意思是,如果您在这一行设置断点,那么您的 Debug-Autos 窗口将显示 x 和 y 的当前值。正如我所说,它只会让你靠近。只是想提供帮助。我认为这不值得一票否决。
P
Peter Mortensen

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

只要我记得(从 Visual Basic 到 VB.NET 的所有版本),您就可以简单地查询函数名称。它像一个在函数开始时隐式声明的局部变量一样“起作用”,并且每当函数通过非返回语句退出时(即 Exit Function 或只是通过)和当然,当使用return语句时。

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

这个小小的 VB.NET 功能(加上它启用的 Exit Function 语句 - C# 没有并且应该的另一个功能)在 defensive programming 我练习的形式中非常有用,我总是将函数名称初始化为失败/默认值作为第一条语句。然后,在任何失败点(通常比成功点更频繁地发生),我可以简单地调用 Exit Function 语句(即无需复制失败/默认表达式甚至常量/变量名称)。


P
Peter Mortensen

The accepted answer 不适用于 Visual Studio 2015,但通过在方法的最后一行放置一个断点并按 F10,它会将返回值的所有表达式放入当地人窗口。


B
Behzad

在 VS2019 中,只需转到 Debug->Windows->Autos 窗口。在那里,您会看到 concat 返回值,如下所示:

https://i.stack.imgur.com/ENccs.png


应该是 VS 2019 及更高版本的公认答案。
P
Peter Mortensen

您可以尝试选择 "someTableAdapter.getSomeData();",右键单击它,然后选择 Quick Watch


P
Peter Mortensen

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

例如,在声明中

return someTableAdapter.getSomeData();

拖放

someTableAdapter.getSomeData()

进入监视窗口,您将看到该值。

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


问题在于:表达式被计算了两次。
并且 watch 表达式不能包含 lambda 表达式,我使用了相当多的。