Come altri hanno già menzionato, non esiste un modo pulito per ottenere quello che stai chiedendo. La nozione di cancellazione era assente dal Asynchronous Programming Model; pertanto, non è stato possibile eseguire il retrofit tramite i convertitori FromAsync
.
Tuttavia, è possibile introdurre la cancellazione per il Task
che avvolge l'operazione asincrona. Questo non annulla l'operazione sottostante - il tuo NetworkStream
continuerà a leggere tutti i byte richiesti dal socket - ma consentirà alla tua applicazione di reagire come se l'operazione fosse annullata, lanciando immediatamente un OperationCanceledException
dal tuo await
(ed eseguendo qualsiasi registrazione continuazione delle attività). Il risultato dell'operazione sottostante, una volta completato, verrà ignorato.
Si tratta di un metodo di estensione di supporto:
public static class TaskExtensions
{
public async static Task<TResult> HandleCancellation<TResult>(
this Task<TResult> asyncTask,
CancellationToken cancellationToken)
{
// Create another task that completes as soon as cancellation is requested.
// http://stackoverflow.com/a/18672893/1149773
var tcs = new TaskCompletionSource<TResult>();
cancellationToken.Register(() =>
tcs.TrySetCanceled(), useSynchronizationContext: false);
var cancellationTask = tcs.Task;
// Create a task that completes when either the async operation completes,
// or cancellation is requested.
var readyTask = await Task.WhenAny(asyncTask, cancellationTask);
// In case of cancellation, register a continuation to observe any unhandled
// exceptions from the asynchronous operation (once it completes).
// In .NET 4.0, unobserved task exceptions would terminate the process.
if (readyTask == cancellationTask)
asyncTask.ContinueWith(_ => asyncTask.Exception,
TaskContinuationOptions.OnlyOnFaulted |
TaskContinuationOptions.ExecuteSynchronously);
return await readyTask;
}
}
e questo è un esempio che utilizza il metodo di estensione per il trattamento di un'operazione come cancellata dopo 300ms:
CancellationTokenSource cts = new CancellationTokenSource();
cts.CancelAfter(TimeSpan.FromMilliseconds(300));
try
{
int bytesRead =
await Task<int>.Factory.FromAsync(this.stream.BeginRead, this.stream.EndRead, buffer, 0, buffer.Length, null)
.HandleCancellation(cts.Token);
}
catch (OperationCanceledException)
{
// Operation took longer than 300ms, and was treated as cancelled.
}
Giusto per chiarire: io voglio annullare un'attività che potrebbe già essere in esecuzione. – Gigi
Sembra che non ci sia sovraccarico di 'FromAsync' che accetta un token di cancellazione. Una possibile soluzione sarebbe quella di aggiungere un altro livello - avviare la propria azione con 'FromAsync' e quindi utilizzare un altro' Task' che supporta la cancellazione dall'esterno per leggere il flusso, all'interno dell'azione personalizzata. – pasty
Hai una buona ragione per non usare 'NetworkStream.ReadAsync', che supporta' CancellationToken'? – avo