註冊取消要求的回呼

了解如何註冊在 IsCancellationRequested 屬性變成 True 時所叫用的委派。 在建立權杖的物件上呼叫 Cancel 時,值會從 False 變更為 True。 使用此技術來取消原本不支援整合取消架構的非同步作業,以及解除封鎖可能會等候非同步作業完成的方法。

注意

啟用 [Just My Code] 時,Visual Studio 在某些情況下會在擲回例外狀況的字行上中斷,並顯示錯誤訊息,指出「使用者程式碼未處理例外狀況」。這個錯誤是良性的。 您可以按 F5 繼續,並查看下面範例中示範的例外狀況處理行為。 若要防止 Visual Studio 在遇到第一個錯誤時就中斷,只要取消核取 [工具]、[選項]、[偵錯]、[一般] 下的 [Just My Code] 核取方塊即可。

範例

在下列範例中,CancelAsync 方法註冊為透過取消語彙基元要求取消時,所要叫用的方法。

using System;
using System.Net;
using System.Threading;
using System.Threading.Tasks;

class CancelWithCallback
{
    static void Main()
    {
        using var cts = new CancellationTokenSource();
        var token = cts.Token;

        _ = Task.Run(async () =>
        {
            using var client = new WebClient();

            client.DownloadStringCompleted += (_, args) =>
            {
                if (args.Cancelled)
                {
                    Console.WriteLine("The download was canceled.");
                }
                else
                {
                    Console.WriteLine("The download has completed:\n");
                    Console.WriteLine($"{args.Result}\n\nPress any key to continue.");
                }
            };

            if (!token.IsCancellationRequested)
            {
                using CancellationTokenRegistration ctr = token.Register(() => client.CancelAsync());

                Console.WriteLine("Starting request\n");
                await client.DownloadStringTaskAsync(new Uri("http://www.contoso.com"));
            }
        }, token);

        Console.WriteLine("Press 'c' to cancel.\n\n");
        if (Console.ReadKey().KeyChar == 'c')
        {
            cts.Cancel();
        }

        Console.WriteLine("\nPress any key to exit.");
        Console.ReadKey();
    }
}
Imports System.Net
Imports System.Threading

Friend Class CancelWithCallback
    Private Shared Sub Main()
        Using cts = New CancellationTokenSource()
            Dim token = cts.Token
            Task.Run(
                Async Function()
                    Using client As New WebClient()
                        AddHandler client.DownloadDataCompleted,
                        Sub(__, args)
                            If args.Cancelled Then
                                Console.WriteLine("The download was canceled.")
                            Else
                                Console.WriteLine($"The download has completed:{vbLf}")
                                Console.WriteLine($"{args.Result}{vbLf}{vbLf}Press any key to continue.")
                            End If
                        End Sub

                        If Not token.IsCancellationRequested Then
                            Dim ctr As CancellationTokenRegistration = token.Register(Sub() client.CancelAsync())
                            Console.WriteLine($"Starting request{vbLf}")
                            Await client.DownloadStringTaskAsync(New Uri("http://www.contoso.com"))
                        End If
                    End Using

                End Function, token)

            Console.WriteLine($"Press 'c' to cancel.{vbLf}{vbLf}")

            If Console.ReadKey().KeyChar = "c"c Then
                cts.Cancel()
            End If

            Console.WriteLine($"{vbLf}Press any key to exit.")
            Console.ReadKey()

        End Using
    End Sub
End Class

如果註冊回呼時,已經要求過取消,仍然保證會呼叫回呼。 在這個特殊案例中,如果沒有任何非同步作業正在進行中,CancelAsync 方法就不會做任何事,所以呼叫方法一定是安全的。

另請參閱