exception-handling - try - raise valueerror




Come posso attendere le attività senza lanciare TaskCanceledExceptions? (2)

Sulla base del suggerimento di João Angelo , ecco un'estensione della classe Task

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace MySharedLibrary.Extensions
{
    public static class TaskExtensions
    {

        // This code is based João Angelo's stackoverflow suggestion https://stackoverflow.com/a/8681687/378115

        // Use this when a CancellationTokenSource is used
        public static void SafeWait(this Task TargetTask, CancellationTokenSource TargetTaskCancellationTokenSource)
        {
            if (TargetTaskCancellationTokenSource.IsCancellationRequested == false)
            {
                TargetTaskCancellationTokenSource.Cancel();
            }
            SafeWait(TargetTask);
        }

        // Use this when no CancellationTokenSource is used
        public static void SafeWait(this Task TargetTask)
        {
            try
            {
                if (TargetTask.IsCanceled == false)
                {
                    TargetTask.Wait();
                }
            }
            catch (AggregateException errors)
            {
                errors.Handle(e => e is TaskCanceledException);
            }
        }

    }
}

Ho un metodo che crea alcuni compiti, e quindi li attende con WaitAll prima di tornare. Il problema è che se queste attività sono state annullate, WaitAll genera un'eccezione AggregateException contenente un sacco di TaskCanceledException .

Ciò significa che WaitAll genererà eccezioni in due diverse circostanze:

  • Eccezioni che indicano un errore reale. Ciò significa che c'era una condizione che non sapevamo come gestire; devono propagarsi come eccezioni non gestite, fino a quando non terminano il processo.
  • Eccezioni che indicano che l'utente ha fatto clic su un pulsante Annulla. Ciò significa che l'attività è stata annullata e pulita, e il programma dovrebbe continuare a funzionare normalmente.

Quest'ultimo si inserisce perfettamente nella definizione di un'eccezione irritante : è un'eccezione generata in una circostanza completamente non eccezionale, quindi devo prenderla per riprendere il normale flusso di controllo. Fortunatamente è facile da catturare, giusto? Basta aggiungere catch (AggregateException) e - oh aspetta, è lo stesso tipo che viene generato quando si verifica un errore fatale.

Devo aspettare che le attività finiscano di funzionare prima di tornare (devo sapere che non usano più le loro connessioni al database, handle di file o altro), quindi ho bisogno di WaitAll o qualcosa di simile. E se qualcuno dei compiti è in errore, desidero che tali eccezioni si propagino come eccezioni non gestite. Non voglio eccezioni per la cancellazione.

Come posso impedire a WaitAll di WaitAll eccezioni per le attività annullate?


AggregateException fornisce un metodo Handle che può essere utilizzato per queste situazioni. Se ad esempio vuoi ignorare TaskCanceledException puoi fare:

var all = new AggregateException(
    new NullReferenceException(),
    new TaskCanceledException(),
    new TaskCanceledException(),
    new InvalidOperationException(),
    new TaskCanceledException());

try
{
    throw all;
}
catch (AggregateException errors)
{
    errors.Handle(e => e is TaskCanceledException);
} 

Se tutte le eccezioni sono di tipo TaskCanceledException , il metodo Handle non genera alcuna eccezione; in caso contrario verrà generata una nuova eccezione AggregateException contenente solo le eccezioni non gestite.





cancellation