2017-03-01 91 views
2

當我跨過斷點在我的代碼我也遇到過調試的奇怪的行爲:奇怪的調試器行爲

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的身體來抓它。任何類型的異常實例(以及明確的null),甚至return而不是throw都是一樣的。

除此之外,即使我刪除與await行。

我試圖從不同的PC運行此代碼段,所以它不是PC麻煩。此外,我認爲這是VS代碼中的錯誤,並試圖從JetBrains的Rider中運行 - 結果相同。

我確定這是異步的事情,但它是如何明確的工作?

回答

5

你的代碼重新產生問題很容易,在「調試」構建,使用Visual Studio 2015年,我只有在Program.Main()添加,通過調用DoSomeWork().Wait();,設置在該方法中設置斷點,並通過它一步。

至於爲什麼發生這種情況,這無疑是由於重寫了async方法和生成的調試數據庫(.pdb)的組合。類似於迭代器方法,將async添加到該方法會導致編譯器將您的方法更改爲狀態機。生成的實際IL看起來只有一點點像原始方法。也就是說,如果你看看它,你可以確定原始代碼的關鍵組成部分,但它現在處在一個大的switch語句中,該語句處理方法在每個await聲明處返回的結果,然後在完成時重新輸入每個期待的表達。

當程序語句出現在throw上時,它確實在方法中的隱含return語句中。只是可執行文件的調試數據庫沒有爲該行提供程序語句。

調試時有一個提示,那就是發生了什麼。當您跨過if聲明時,您會注意到它直接轉到throw聲明。如果輸入if語句塊爲確實,則下一個程序語句行實際上是該塊的開始括號,而不是程序語句。

您還可以添加例如一個Console.WriteLine()在方法結束時,這將給調試器足夠的信息同步,而不會顯示在錯誤的行號。

有關編譯器如何處理async方法的更多信息,請參閱Is the new C# async feature implemented strictly in the compiler以及其中提供的鏈接(包括Jon的關於該主題的系列文章)。

+0

你說「添加'async'和至少一個'await'」,但我轉載,即使沒有在所有 – Altav1sta

+0

@ Altav1sta用'await'行:好吧,那麼似乎編譯器生成的狀態機的所有'異步「方法。我在你的文章中解釋了「它的作用」,意思是調試器做了_right_事情,而不是錯誤的事情。我想這不是你的意思。 –

+0

是的,抱歉讓人困惑。我的意思是__it的工作原理是相同的,即我輸入'if' body,但是異常並沒有真正拋出 – Altav1sta