如何:注册取消请求的回调

下面的示例演示如何注册当 IsCancellationRequested 属性由于对创建标记的对象调用 Cancel 而变为 true 时将调用的委托。 使用此技术来取消本质上不支持统一取消框架的异步操作,以及取消阻塞可能等待异步操作完成的方法。

注意注意

当启用“仅我的代码”时,在某些情况下,Visual Studio 将在引发异常的行上中断运行,并显示错误消息“异常未由用户代码处理”。此错误是良性的。可以按 F5 从中断处继续运行,并查看在以下示例中演示的异常处理行为。若要阻止 Visual Studio 在出现第一个错误时中断运行,只需在“工具”->“选项”->“调试”->“常规”下,取消选中“仅我的代码”复选框即可。

示例

在下面的示例中,CancelAsync 方法注册为通过取消标记请求取消时调用的方法。



Class CancelWithCallback


    Shared Sub Main()

        Dim cts As New CancellationTokenSource()

        ' Start cancelable task.
        Dim t As Task = Task.Factory.StartNew(Sub() DoWork(cts.Token))

        Console.WriteLine("Press 'c' to cancel.")
        Dim ch As Char = Console.ReadKey().KeyChar
        If ch = "c"c Then

            cts.Cancel()
        End If
        Console.WriteLine("Press any key to exit.")
        Console.ReadKey()
    End Sub

    Shared Sub DoWork(ByVal token As CancellationToken)

        Dim wc As New WebClient()

        ' Create an event handler to receive the result.
        AddHandler wc.DownloadStringCompleted, Sub(obj, e)

                                                   ' Checks status of WebClient, not external token
                                                   If e.Cancelled = False Then

                                                       Console.WriteLine(e.Result + "\r\nPress any key.")

                                                   Else
                                                       Console.WriteLine("Download was canceled.")
                                                   End If
                                               End Sub

        token.Register(Sub() wc.CancelAsync())

        Console.WriteLine("Starting request")
        wc.DownloadStringAsync(New Uri("https://www.contoso.com"))
    End Sub
End Class
namespace Cancel3
{
    using System;
    using System.Net;
    using System.Threading;
    using System.Threading.Tasks;

    class CancelWithCallback
    {

        static void Main(string[] args)
        {
            var cts = new CancellationTokenSource();

            // Start cancelable task.
            Task t = Task.Factory.StartNew(() =>
            {
                DoWork(cts.Token);
            });

            Console.WriteLine("Press 'c' to cancel.");
            char ch = Console.ReadKey().KeyChar;
            if (ch == 'c')
            {
                cts.Cancel();
            }
            Console.WriteLine("Press any key to exit.");
            Console.ReadKey();
        }

        static void DoWork(CancellationToken token)
        {
            WebClient wc = new WebClient();

            // Create an event handler to receive the result.
            wc.DownloadStringCompleted += (obj, e) =>
            {
                // Checks status of WebClient, not external token
                if (!e.Cancelled)
                {
                    Console.WriteLine(e.Result + "\r\nPress any key.");
                }
                else
                    Console.WriteLine("Download was canceled.");
            };

            // Do not initiate download if the external token
            // has already been canceled.
            if (!token.IsCancellationRequested)
            {
                // Register the callback to a method that can unblock.
                // Dispose of the CancellationTokenRegistration object
                // after the callback has completed.
                using (CancellationTokenRegistration ctr = token.Register(() => wc.CancelAsync()))
                {
                    Console.WriteLine("Starting request");
                    wc.DownloadStringAsync(new Uri("https://www.contoso.com"));
                }
            }
        }
    }
}

如果注册回调时已请求取消,则仍一定会调用回调。 在此特定情况下,如果没有异步操作正在进行,则 CancelAsync 方法不会执行任何操作,因此调用该方法始终是安全的。

请参见

概念

取消