为什么Visual Studio调试器不显示await关键字生成的状态机代码?

时间:2016-06-06 19:48:33

标签: .net visual-studio async-await visual-studio-2015

当我在我正在等待的方法体中设置断点时,Visual Studio调试器显示一个没有任何C#编译器生成代码的调用堆栈。

请查看下面的图片,其中显示了我的简单async方法和调用堆栈。

enter image description here

请注意,没有调用MoveNext或初始化状态机对象或调用堆栈中的TaskAwaiter<TResult>AsyncTaskOfTMethodBuilder

为什么会这样?就像在IL Spy中一样,Visual Studio中是否有一些设置可以切换,以便在调试会话正在进行时在调用堆栈和编辑器中显示状态机代码?

我突然想起重写的按钮点击处理程序代码上有一个DebuggerStepThroughAttribute来实例化状态机。但我不确定这是否是它从调试器中隐藏的原因。这个不应该只是灰色了调用堆栈中编译器生成的方法的堆栈帧吗?

DebuggerHiddenAttribute不是使代码对调试器不可见的那个吗?

1 个答案:

答案 0 :(得分:2)

这里有几点需要注意。

首先,你有2个线程在玩:

  1. 主线程,运行消息泵并拥有其中包含按钮的窗口
  2. 正在运行任务的线程
  3. 一个线程内的调用堆栈决不会反映创建它的线程当前正在做什么。

    如果你检查可以在调试器中显示所有线程及其callstack的调试器窗格,你最多会看到两个线程及其callstack。

    但是,这只会显示按钮事件处理程序,如果执行此方法的线程在调试器遇到断点时仍在方法中。由于旋转新线程的开销,这很可能不正确。

    原因是async/await 在遇到asyncawait方法返回。当单独的线程开始执行您的委托时,按钮事件处理程序方法很可能已返回。

    即使你手动为你的委托启动一个线程并加入(等待)该线程,你也不会在 callstack 中看到这个,但是你应该在其他调试器中看到它线程及其调用栈的窗格。