23

いくつかのタスクを作成し、WaitAllでそれらを待機してから戻るメソッドがあります。問題は、これらのタスクがキャンセルされた場合、WaitAllが多数のTaskCanceledExceptionを含むAggregateExceptionをスローすることです。

これは、WaitAllが2つの異なる状況で例外をスローすることを意味します。

  • 真のエラーを示す例外。これらは、処理方法がわからない状態があったことを意味します。最終的にプロセスを終了するまで、未処理の例外として伝播する必要があります。
  • ユーザーが[キャンセル]ボタンをクリックしたことを示す例外。これは、タスクがキャンセルされてクリーンアップされ、プログラムが正常に実行され続けることを意味します。

後者は、厄介な例外の定義に正直に当てはまります。これは、完全に例外ではない状況でスローされる例外であるため、通常の制御フローを再開するには、それをキャッチする必要があります。幸いなことに、捕まえるのは簡単ですよね?追加catch (AggregateException)して-ああ、待ってください。これは、致命的なエラーが発生したときにスローされるのと同じタイプです。

タスクが実行を終了するのを待ってから戻る必要があるので(データベース接続やファイルハンドルなどを使用していないことを知る必要があります)、WaitAllなどが必要です。また、いずれかのタスクに障害が発生した場合、それらの例外を未処理の例外として伝播させたいと思います。キャンセルの例外は必要ありません。

WaitAllキャンセルされたタスクの例外がスローされないようにするにはどうすればよいですか?

4

2 に答える 2

28

は、これらの状況に使用できるメソッドをAggregateException提供します。Handleたとえば、無視したい場合は、次のTaskCanceledExceptionことができます。

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);
} 

すべての例外がタイプのTaskCanceledException場合、Handleメソッドは例外をスローしません。AggregateExceptionそれ以外の場合は、未処理の例外のみを含むnewがスローされます。

于 2011-12-30T16:34:41.283 に答える
1

JoãoAngeloの提案に基づいて、ここにタスククラスの拡張機能があります

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);
            }
        }

    }
}
于 2014-10-22T11:20:11.537 に答える