当我在正在等待的方法主体中设置断点时,Visual Studio 调试器显示一个调用堆栈,其中没有任何 C# 编译器生成的代码。
请看下图,这是我简单的async
方法和调用堆栈。
请注意,没有调用 MoveNext
或初始化状态机对象或TaskAwaiter<TResult>
或AsyncTaskOfTMethodBuilder
在调用堆栈中。
为什么会这样呢?就像 IL Spy 中一样,Visual Studio 中是否有一些设置可以切换,使其在调试 session 正在进行时在调用堆栈和编辑器中显示状态机代码?
我突然想起有一个DebuggerStepThroughAttribute
在重写的按钮上单击实例化状态机的处理程序代码。但我不确定这是否是它对调试器隐藏的原因。难道这不应该只是将调用堆栈中编译器生成的方法的堆栈框架变灰吗?
不是 DebuggerHiddenAttribute
使代码对调试器不可见的那个?
最佳答案
这里有几件事需要注意。
首先,您有 2 个线程正在运行:
- 主线程,运行消息泵并拥有包含按钮的窗口
- 正在运行任务的线程
一个线程内的调用堆栈绝不会反射(reflect)创建它的线程当前正在执行的操作。
如果您检查可以在调试器中显示所有线程及其调用堆栈的调试器 Pane ,您最多会看到两个线程及其调用堆栈。
但是,如果调试器命中断点时执行此方法的线程仍在该方法中,则这只会显示按钮事件处理程序。由于启动新线程的开销,这很可能不是真的。
原因是 async/await
当它遇到 await
时,从 async
方法返回 。当单独的线程开始执行您的委托(delegate)时,按钮事件处理程序方法很可能已经返回。
即使您手动为委托(delegate)启动一个线程并加入(等待)该线程,您也不会在调用堆栈中看到它,但您绝对应该在其他调试器中看到它线程及其调用堆栈的 Pane 。
关于.net - 为什么 Visual Studio 调试器不显示由 wait 关键字生成的状态机代码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37665700/