Registro de devoluciones de llamada como solicitudes de cancelación
Obtenga información sobre cómo registrar un delegado que se invocará cuando una propiedad IsCancellationRequested se convierta en true. El valor cambia de "false" a "true" cuando se realiza una llamada a Cancel en el objeto que creó el token. Use esta técnica para cancelar operaciones asincrónicas que no admiten el marco de cancelación unificado de forma nativa, y para desbloquear métodos que podrían estar esperando que una operación asincrónica finalice.
Nota
Si la opción "Solo mi código" está habilitada, a veces Visual Studio se interrumpe en la línea que inicia la excepción y muestra un mensaje de error que indica "excepción no controlada por el código de usuario". Se trata de un error benigno. Puede presionar F5 para continuar y ver el comportamiento de control de excepciones que se muestra en estos ejemplos. Para evitar que Visual Studio se interrumpa con el primer error, desactive la casilla "Solo mi código" en Herramientas, Opciones, Depurar, General.
Ejemplo
En el ejemplo siguiente, el método CancelAsync se registra como el método que se invocará cuando se solicite la cancelación mediante el token de cancelación.
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
Si ya ha solicitado la cancelación al registrar la devolución de llamada, aún se garantiza que se llamará a la devolución de llamada. En este caso, 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.