Cómo: Registrar devoluciones de llamadas de solicitudes de cancelación
En el ejemplo siguiente, se muestra cómo registrar un delegado que se invocará cuando una propiedad IsCancellationRequested sea true debido a una llamada a Cancel en el objeto que creó el token. Emplee esta técnica para cancelar operaciones asincrónicas que no admiten el marco de cancelación unificada de forma nativa y para desbloquear métodos que podrían estar esperando la finalización de una operación asincrónica.
![]() |
---|
Cuando está habilitada la opción "Solo mi código", en algunos casos, Visual Studio se interrumpe en la línea que produce la excepción y muestra el mensaje de error "Excepción no controlada por el código de usuario". Este error es benigno.Puede presionar F5 para continuar y ver el comportamiento de control de excepciones que se muestra en los ejemplos siguientes.Para evitar que Visual Studio se interrumpa con el primer error, desactive la casilla "Solo mi código" bajo Herramientas, Opciones, Depuración, General. |
Ejemplo
En el ejemplo siguiente, el método CancelAsync se registra como el método que se va a invocar cuando se solicite la cancelación a través del token de cancelación.
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"));
}
}
}
}
}
Si ya se ha solicitado la cancelación cuando se registra la devolución de llamada, se garantiza que se sigue llamando a la devolución de llamada. En este caso concreto, el método CancelAsync no hará nada si no hay ninguna operación asincrónica en curso, por lo que siempre es seguro llamar al método.