异步方法中的奇怪调试器行为 [英] Strange debugger behaviour in async method

查看:65
本文介绍了异步方法中的奇怪调试器行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我跨过代码中的断点时,遇到了调试器的奇怪行为:

When I stepped over breakpoints in my code I have encountered strange behaviour of debugger:

public async Task DoSomeWork()
{
     await Task.Run(() => { Thread.Sleep(1000); });

     var test = false;
     if (test)
     {
          throw new Exception("Im in IF body!");
     }
}

调试器进入if主体.值得注意的是,该异常并未真正引发,而是看起来像是这样.因此,如果将断点放在throw上,则无法重现.您必须将其放置在上方并下移到if主体才能抓住它.

Debugger goes into if body. It's remarkable that the exception is not really thrown but just looks like it is. So you can't reproduce that if you place breakpoint right on throw. You must place it above and step down to the if body to catch it. The same works on any kind of exception instance (as well as explicit null) and even on return instead of throw.

即使我用await删除行,它也能正常工作.

Besides that it works even if I remove line with await.

我试图从不同的PC运行此代码段,因此这不是PC的麻烦.我还认为这是VS代码中的错误,并尝试从JetBrains在Rider中运行它-结果相同.

I tried to run this code snippet from different PCs so its not a PC trouble. Also I have thought it is bug in VS code and tried to run it in Rider from JetBrains - the same result.

我确定这是异步的东西,但是它是如何显式工作的?

I'm sure it's the async thing but how it explicitly works?

推荐答案

您的代码可以使用Visual Studio 2015在"Debug" 构建中轻松重现该问题.我只需添加Program.Main()(调用DoSomeWork().Wait();)在方法中设置一个断点并逐步执行.

Your code reproduces the issue easily, in a "Debug" build, using Visual Studio 2015. I had only to add in Program.Main(), with a call to DoSomeWork().Wait();, set a breakpoint in the method and step through it.

关于发生这种情况的原因,无疑是由于重新编写了async方法和生成调试数据库(.pdb)的结合.与迭代器方法类似,向该方法添加async会使编译器将您的方法更改为状态机.生成的实际IL看起来只有点像原始方法.也就是说,如果您看一下它,就可以识别原始代码的关键组成部分,但是它现在位于一个大的switch语句中,该语句处理该方法在每个await语句返回时发生的情况,然后重新执行该操作.在每个等待的表达式完成时输入.

As for why it happens, this is undoubtedly due to the combination of the async method being rewritten and the debugging database (.pdb) generated. Similar to iterator methods, adding async to the method causes the compiler to change your method into a state machine. The actual IL that's generated looks only a little bit like the original method. That is, if you look at it, you can identify the key components of the original code, but it's now in a big switch statement that handles what happens as the method returns at each await statement, and then is re-entered with the completion of each awaited expression.

当program语句似乎位于throw上时,它实际上位于方法中的隐式return语句上.只是可执行文件的调试数据库没有为该行提供程序语句.

When the program statement appears to be on the throw, it's really at the implicit return statement in the method. It's just that the debugging database for the executable doesn't provide a program statement for that line.

在调试时有一个提示,那就是正在发生的事情.当您跳过if语句时,您会发现它直接进入throw语句.如果输入if语句块确实是 ,则下一个程序语句行实际上将是该块的开头大括号,而不是程序语句.

There's a hint, when debugging, that that's what's happening. When you step over the if statement, you'll notice it goes straight to the throw statement. If the if statement block were really being entered, the next program statement line would actually be the opening brace for the block, not the program statement.

您还可以添加例如在方法末尾输入Console.WriteLine(),这将为调试器提供足够的信息以进行同步,而不会显示错误的行号.

You can also add e.g. a Console.WriteLine() at the end of the method, and that will give the debugger enough information to sync up and not show you at the wrong line number.

有关编译器如何处理async方法的其他信息,请参见新的C#异步功能是否严格在编译器中实现以及那里提供的链接(包括Jon关于该主题的系列文章).

For additional information on how async methods are handled by the compiler, see Is the new C# async feature implemented strictly in the compiler, and the links provided there (including Jon's series of articles on the topic).

这篇关于异步方法中的奇怪调试器行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆