Share via


逐步解說:搭配非同步方法使用偵錯工具

您可以使用非同步功能,您可以呼叫非同步方法,而不需使用回呼或分割您的多個方法或 Lambda 運算式的程式碼。 若要使程式碼非同步,您呼叫非同步方法而非使用同步方法並加入一些關鍵字加入程式碼。 如需詳細資訊,請參閱使用 Async 和 Await 設計非同步程式 (C# 和 Visual Basic)

在 Visual Studio 偵錯工具,您可以使用 [逐步執行]、 [步驟] 和 [步驟] 命令與 Async 功能。 您也可以繼續使用中斷點,特別是檢視包含 Await 運算子的陳述式的控制流程。 在這個逐步解說中,您將完成下列工作,您可以依任何順序執行。

  • 示範在等候陳述式的控制流程使用中斷點。

  • 了解 [逐步執行] 和 [步驟] 命令的行為在包含 Await 運算子的陳述式。

  • 因此,使用它從非同步方法的內部時,所發生的 [步驟] 命令的行為。

顯示控制流程的中斷點

如果您將標記為已使用 Async (Visual Basic) 或 (C#) 非同步 修飾詞的方法,在方法中使用 等候 (Visual Basic) 或 等候 (C#) 運算子。 若要建立等候運算式,您使 Await 運算子與工作。 當等候運算式工作時,會呼叫目前的方法會立即完成並傳回不同的工作。 當與 Await 運算子時的工作完成,執行在相同方法繼續。 如需詳細資訊,請參閱非同步程式中的控制流程 (C# 和 Visual Basic)

注意事項注意事項

非同步方法傳回給呼叫端時,可能會遇到不完整時或是在非同步方法的結尾先等候的物件,最先出現。

注意事項注意事項

在這些範例中的主控台應用程式使用 Wait 方法可防止應用程式終止的 Main。因為死結情況可能發生,您不應該使用 Wait 方法在主控台應用程式外。

示範發生了什麼的下列程序中設定中斷點,當應用程式執行等候陳述式。 您也可以將示範控制流程將 Debug.WriteLine 陳述式。

  1. 建立主控台應用程式,然後將下列程式碼貼入其中:

    ' Breakpoints to show control flow.
    Imports System.Threading.Tasks
    
    Module Module1
        Sub Main()
            Dim theTask = ProcessAsync()
            Dim x = 0 ' set breakpoint
            theTask.Wait()
        End Sub
    
        Async Function ProcessAsync() As Task
            Dim result = Await DoSomethingAsync()  ' set breakpoint
    
            Dim y = 0 ' set breakpoint
        End Function
    
        Async Function DoSomethingAsync() As Task(Of Integer)
            Await Task.Delay(1000)
            Return 5
        End Function
    End Module
    
    // Breakpoints to show control flow.
    using System.Threading.Tasks;
    
    class Program
    {
        static void Main(string[] args)
        {
            Task theTask = ProcessAsync();
            int x = 0;  // set breakpoint
            theTask.Wait();
        }
    
        static async Task ProcessAsync()
        {
            var result = await DoSomethingAsync();  // set breakpoint
    
            int y = 0;  // set breakpoint
        }
    
        static async Task<int> DoSomethingAsync()
        {
            await Task.Delay(1000);
            return 5;
        }
    }
    
  2. 設定以「設定中斷點」註解結束三行的偵錯中斷點。

  3. 選擇 F5 鍵或選取 [偵錯],請在功能表列上的 [啟動偵錯] 執行應用程式。

    應用程式在包含 Await 運算子的行進入 ProcessAsync 方法而中斷。

  4. 再次選擇 F5 鍵。

    由於應用程式中包含 Await 運算子的陳述式停止,應用程式會立即結束非同步方法並傳回工作。 因此,應用程式就會結束 ProcessAsync 方法而中斷。在呼叫的方法 (Main) 的中斷點。

  5. 再次選擇 F5 鍵。

    在 DoSomethingAsync 方法完成時,程式碼會在呼叫方法的等候陳述式之後繼續。 因此,應用程式中斷在 ProcessAsync 方法中的中斷點。

    當 DoSomethingAsync 最初等候, ProcessAsync 方法會結束並傳回工作。 當等候的 DoSomethingAsync 方法會完成,等候陳述式的評估產生傳回值 DoSomethingAsync。 DoSomethingAsync 方法在 C# 中定義傳回在 Visual Basic 中的 Task (Of Integer)Task<int> ,因此,在其傳回陳述式的值是整數。 如需詳細資訊,請參閱非同步方法的傳回型別 (C# and Visual Basic)

JJ155813.collapse_all(zh-tw,VS.110).gif取得然後等候工作

在 ProcessAsync 方法中,陳述式 Dim result = Await DoSomethingAsync() (Visual Basic) 或 var result = await DoSomethingAsync(); (C#) 為下列兩個陳述式的縮小:

Dim theTask = DoSomethingAsync()
Dim result = Await theTask
var theTask = DoSomethingAsync();
var result = await theTask;

第一個程式碼會呼叫非同步方法並傳回工作。 該工作與下一行程式碼的 Await 運算子。 等候陳述式結束方法 (ProcessAsync) 和傳回不同的工作。 當與 Await 運算子時的工作完成時,程式碼在方法 (ProcessAsync) 繼續等候陳述式之後。

當等候陳述式立即傳回不同的工作時,該工作是包含 Await 運算子的非同步方法傳回的引數 (ProcessAsync)。 由等候傳回這些工作時,會發生在相同方法之後的等候,是的程式碼執行該工作為何與等候的工作不同。

逐步執行並逐步執行

[逐步執行] 命令逐步執行方法,不過, [步驟] 命令會呼叫方法的下一行執行方法呼叫然後中斷。 如需詳細資訊,請參閱[NIB] 程式碼逐步執行概觀

下列程序顯示出現,當您選取 [逐步執行] 或 [步驟] 命令在等候陳述式。

  1. 以下列程式碼取代在主控台應用程式的程式碼。

    ' Step Into and Step Over Example
    Imports System.Threading.Tasks
    
    Module Module1
        Sub Main()
            ProcessAsync.Wait()
        End Sub
    
        Async Function ProcessAsync() As Task
            Dim result = Await DoSomethingAsync()  ' Step Into or Step Over from here
    
            Dim y = 0
        End Function
    
        Async Function DoSomethingAsync() As Task(Of Integer)
            Await Task.Delay(1000)
            Return 5
        End Function
    End Module
    
    // Step Into and Step Over Example.
    using System.Threading.Tasks;
    
    class Program
    {
        static void Main(string[] args)
        {
            ProcessAsync().Wait();
        }
    
        static async Task ProcessAsync()
        {
            var result = await DoSomethingAsync();  // Step Into or Step Over from here
    
            int y = 0;
        }
    
        static async Task<int> DoSomethingAsync()
        {
            await Task.Delay(1000);
            return 5;
        }
    }
    
  2. 選擇 F11 鍵或選取 [偵錯],請在功能表列上的 [逐步執行] 開始 Step Into 命令的示範含有 Await 運算子的陳述式。

    應用程式在第一行開始並中斷,是在 Visual Basic 或 Main 方法左大括號的 C# 中的 Sub Main() 。

  3. 選擇 F11 鍵三倍。

    應用程式應該會在 ProcessAsync 方法的等候陳述式。

  4. 選擇 F11 鍵。

    應用程式在第一行輸入 DoSomethingAsync 方法而中斷。 這種行為的發生,即使,而在 await 陳述式中,應用程式會立即回到呼叫的方法 (Main)。

  5. 選取到應用程式的 Keep F11 鍵回 ProcessAsync 方法等候的陳述式。

  6. 選擇 F11 鍵。

    應用程式必須在等候陳述式的分行符號。

  7. 在功能表列上,選擇 [偵錯]],則 [停止偵錯] 停止執行。

    下列步驟示範 [步驟] 命令在等候陳述式。

  8. 選擇 F11 鍵四次或選取 [偵錯],請在功能表列上的 [逐步執行] 四次。

    應用程式應該會在 ProcessAsync 方法的等候陳述式。

  9. 選擇 F10 鍵或選取 [偵錯],請在功能表列上的 [步驟] 。

    執行中斷之後等候陳述式的行。 這種行為的發生,即使應用程式立即傳回給呼叫的方法 (Main) 在等候陳述式。 Step Over 命令也不進入 DoSomethingAsync 方法的執行,如預期般運作。

  10. 在功能表列上,選擇 [偵錯]],則 [停止偵錯] 停止執行。

    在下列步驟中,會顯示 [逐步執行] 和 [步驟] 命令的行為稍有不同,因為 Await 運算子是在從呼叫中不同的行至非同步方法時。

  11. 在 ProcessAsync 方法中,以下列程式碼取代等候陳述式。 原始等候陳述式是下列兩個陳述式的合約。

    Dim theTask = DoSomethingAsync()
    Dim result = Await theTask
    
    var theTask = DoSomethingAsync();
    var result = await theTask;
    
  12. 選擇 F11 鍵或選取 [偵錯],請在功能表列上多次的 [逐步執行] 至程式碼開始執行和步驟。

    在對 DoSomethingAsync的呼叫, [ [逐步執行] 命令在 DoSomethingAsync 方法中),,而 [步驟] 命令移至下一個陳述式,如預期般運作。 在等候陳述式,兩個命令中斷之後等候的陳述式。

跳離函式

在不是的非同步方法, [步驟] 命令會在之後呼叫方法的程式碼呼叫的方法中斷。 如需非同步方法,執行在呼叫的方法中斷的邏輯較為複雜和該邏輯取決於 [步驟] 命令是否在非同步方法的第一行。

  1. 以下列程式碼取代在主控台應用程式的程式碼。

    ' Step Out Example
    Imports System.Threading.Tasks
    
    Module Module1
        Sub Main()
            ProcessAsync.Wait()
        End Sub
    
        Async Function ProcessAsync() As Task
            Dim theTask = DoSomethingAsync()
            Dim z = 0
            Dim result = Await theTask
        End Function
    
        Async Function DoSomethingAsync() As Task(Of Integer)
            Debug.WriteLine("before")  ' Step Out from here
            Await Task.Delay(1000)
            Debug.WriteLine("after")
            Return 5
        End Function
    End Module
    
    // Step Out Example.
    using System.Diagnostics;
    using System.Threading.Tasks;
    
    class Program
    {
        static void Main(string[] args)
        {
            ProcessAsync().Wait();
        }
    
        static async Task ProcessAsync()
        {
            var theTask = DoSomethingAsync();
            int z = 0;
            var result = await theTask;
        }
    
        static async Task<int> DoSomethingAsync()
        {
            Debug.WriteLine("before");  // Step Out from here
            await Task.Delay(1000);
            Debug.WriteLine("after");
            return 5;
        }
    }
    
  2. 設定 Debug.WriteLine("before") 行設定中斷點在 DoSomethingAsync 方法。

    這是為了示範 [步驟] 命令的行為從一行中不是第一行的非同步方法。

  3. 選擇 F5 鍵或選取 [偵錯],請在功能表列上的 [啟動偵錯] 啟動應用程式。

    程式碼會在 DoSomethingAsync 方法的 Debug.WriteLine("before") 中斷。

  4. 選取 Shift+F11 鍵或選取 [偵錯],請在功能表列上的 [步驟] 。

    應用程式在呼叫的方法會中斷與目前方法的工作等候陳述式。 因此,應用程式會在 ProcessAsync 方法中等候陳述式內容中斷。 應用程式在 Dim z = 0 (Visual Basic) 或 int z = 0; (C#) 中斷,為程式碼之後呼叫 DoSomethingAsync 方法。

  5. 選取 [偵錯],請在功能表列上的 [停止偵錯] 停止執行。

    下列步驟示範發生的事情,當您從非同步方法的第一行中的 [步驟] 。

  6. 移除現有的中斷點,然後在 DoSomethingAsync 方法的第一行設定中斷點。

    在 C# 中,將在 DoSomethingAsync 方法的左邊大括號的中斷點。 在 Visual Basic 中,將該行的中斷點會包含 Async Function DoSomethingAsync() As Task(Of Integer)。

  7. 選擇 F5 鍵啟動應用程式。

    程式碼在 DoSomethingAsync 方法的第一個分行符號。

  8. 在功能表列上,選擇 [偵錯]],則 [視窗], [輸出]。

    [輸出] 視窗隨即開啟。

  9. 選取 Shift+F11 鍵或選取 [偵錯],請在功能表列上的 [步驟] 。

    應用程式繼續執行,直到非同步方法到達第一個等候,應用程式會中斷在後面的陳述式。 因此,應用程式在 Dim the Task = DoSomethingAsync() (Visual Basic) 或 var theTask = DoSomethingAsync(); (C#) 中斷。 「,」訊息會顯示在輸出視窗之前,不過, 「,」訊息不會出現。

  10. 選擇 F5 鍵繼續執行應用程式。

    應用程式會繼續依照非同步呼叫的函式中的陳述式 (DoSomethingAsync) 的等候陳述式。 < 在訊息之後出現在輸出視窗中。

請參閱

概念

[NIB] 程式碼逐步執行概觀