如何:註冊取消要求的回呼How to: Register Callbacks for Cancellation Requests

下列範例示範如何註冊委派,當因為在建立權杖的物件上呼叫 Cancel,而使 IsCancellationRequested 屬性變成 true 時,將會叫用此委派。The following example shows how to register a delegate that will be invoked when a IsCancellationRequested property becomes true due to a call to Cancel on the object that created the token. 您可以使用這個技巧來取消原本不支援整合取消架構的非同步作業,以及解除封鎖可能會等候非同步作業完成的方法。Use this technique for cancelling asynchronous operations that do not natively support the unified cancellation framework, and for unblocking methods that might be waiting for an asynchronous operation to finish.

注意

啟用 [Just My Code] 時,Visual Studio 在某些情況下會在擲回例外狀況的字行上中斷,並顯示錯誤訊息,指出「使用者程式碼未處理例外狀況」。When "Just My Code" is enabled, Visual Studio in some cases will break on the line that throws the exception and display an error message that says "exception not handled by user code." 這個錯誤是良性的。This error is benign. 您可以按 F5 鍵繼續,並查看下面範例中示範的例外狀況處理行為。You can press F5 to continue from it, and see the exception-handling behavior that is demonstrated in the examples below. 若要防止 Visual Studio 在遇到第一個錯誤時就中斷,只要取消核取 [工具]、[選項]、[偵錯]、[一般]**** 下的 [Just My Code] 核取方塊即可。To prevent Visual Studio from breaking on the first error, just uncheck the "Just My Code" checkbox under Tools, Options, Debugging, General.

範例Example

在下列範例中,CancelAsync 方法註冊為透過取消語彙基元要求取消時,所要叫用的方法。In the following example, the CancelAsync method is registered as the method to be invoked when cancellation is requested through the cancellation token.

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

class CancelWithCallback
{
   static void Main()
   {
      var cts = new CancellationTokenSource();
      var token = cts.Token;
      
      // Start cancelable task.
      Task t = Task.Run( () => {
                    WebClient wc = new WebClient();

                    // Create an event handler to receive the result.
                    wc.DownloadStringCompleted += (obj, e) => {
                               // Check status of WebClient, not external token.
                               if (!e.Cancelled) {
                                  Console.WriteLine("The download has completed:\n");
                                  Console.WriteLine(e.Result + "\n\nPress any key.");
                               }
                               else {
                                  Console.WriteLine("The 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.
                       using (CancellationTokenRegistration ctr = token.Register(() => wc.CancelAsync()))
                       {
                          Console.WriteLine("Starting request\n");
                          wc.DownloadStringAsync(new Uri("http://www.contoso.com"));
                       }
                    }
               }, token);

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

      Console.WriteLine("Press any key to exit.");
      Console.ReadKey();
      cts.Dispose();
   }
}
Imports System.Threading
Imports System.Threading.Tasks
Imports System.Net

Class CancelWithCallback
    Shared Sub Main()
        Dim cts As New CancellationTokenSource()
        Dim token As CancellationToken = cts.Token
        
        ' Start cancelable task.
        Dim t As Task = Task.Run(
           Sub()
              Dim wc As New WebClient()
              
              ' Create an event handler to receive the result.
              AddHandler wc.DownloadStringCompleted,
                         Sub(obj, e)
                            ' Check status of WebClient, not external token.
                            If Not e.Cancelled Then
                               Console.WriteLine("The download has completed:" + vbCrLf)
                               Console.WriteLine(e.Result + vbCrLf + vbCrLf + "Press any key.")
                            Else
                               Console.WriteLine("Download was canceled.")
                            End If
                          End Sub
              Using ctr As CancellationTokenRegistration = token.Register(Sub() wc.CancelAsync())
                 Console.WriteLine("Starting request..." + vbCrLf)
                 wc.DownloadStringAsync(New Uri("http://www.contoso.com"))
              End Using
           End Sub, token)

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

        If ch = "c"c Then
            cts.Cancel()
        End If
        Console.WriteLine("Press any key to exit.")
        Console.ReadKey()
        cts.Dispose()
    End Sub
End Class

如果註冊回呼時,已經要求過取消,仍然保證會呼叫回呼。If cancellation has already been requested when the callback is registered, the callback is still guaranteed to be called. 在這個特殊案例中,如果沒有任何非同步作業正在進行中,CancelAsync 方法就不會做任何事,所以呼叫方法一定是安全的。In this particular case, the CancelAsync method will do nothing if no asynchronous operation is in progress, so it is always safe to call the method.

另請參閱See also