【问题标题】:Can I find out the return value before returning while debugging in Visual Studio?在 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 年的答案是什么?这些答案已经过时了。

标签: c# visual-studio visual-studio-debugging


【解决方案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

【讨论】:

【解决方案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】:

如果您进入菜单ToolsOptions,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,它是在调试模式(菜单 DebugWindows自动)。

    【讨论】:

    • @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 返回值:

                【讨论】:

                  猜你喜欢
                  • 2012-01-13
                  • 2011-06-27
                  • 2019-05-02
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多