3

タスクでスローされた例外を処理済みとしてマークするにはどうすればよいですか。Wait()問題は、タスクのメソッドを呼び出すと、かなり前にAggregateException既に処理した場合でもスローされることです。AggregateException次のコード スニペットは、解決したい問題を示しています。元のコードは、コードの一部で処理し、コードの別の部分でメソッドAggregateExceptionを呼び出します。Wait()しかし、問題は同じです。

static void Main(string[] args)
{
    Task task = null;

    try
    {
        task = new Task(() =>
        {
            Console.WriteLine("Task started");
            Thread.Sleep(1000);
            throw new InvalidOperationException("my test exception");
        });

        task.ContinueWith(t => 
        {
            Console.WriteLine("Task faulted");
            AggregateException ae = t.Exception;
            ae.Flatten().Handle(ex =>
            {
                if (typeof(InvalidOperationException) == ex.GetType())
                {
                    Console.WriteLine("InvalidOperationException handled --> " + ex.Message);
                    return true;
                }

                return false;
            });
        }, TaskContinuationOptions.OnlyOnFaulted);

        task.Start();
        Thread.Sleep(2000);
        task.Wait();
    }
    catch (AggregateException ae)
    {
        Console.WriteLine("AggregateException thrown again!!! Why???");
        ae.Flatten().Handle(ex =>
            {
                Console.WriteLine(ex.Message);
                return true;
            });              
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }

    Console.WriteLine("Finished");
    Console.Read();
}

上記のコードは、次の出力を生成します。

  • タスク開始
  • タスクが失敗しました
  • InvalidOperationException の処理 --> 私のテスト例外
  • AggregateException が再びスローされました!!! どうして???
  • 私のテスト例外
  • 終了した
4

1 に答える 1

2

失敗したタスクがWaited になると、例外が再スローされます。ときどき例外がスローされるだけでは、信頼性の低い設計になります。

ただし、例外を処理する継続を追加していて、それを再度スローしたくない場合は、Waitそのタスクを再度実行しないでください。Wait代わりに継続タスク (現在使用していないもの) を使用してください。元のタスクが完了した後にのみ完了し、結果が必要な場合は、継続してそれを返すだけです。このようにして、例外は 1 回だけ処理されます。

Task continuation = task.ContinueWith(t => 
{
    Console.WriteLine("Task faulted");
    AggregateException ae = t.Exception;
    ae.Flatten().Handle(ex =>
    {
        if (typeof(InvalidOperationException) == ex.GetType())
        {
            Console.WriteLine("InvalidOperationException handled --> " + ex.Message);
            return true;
        }

        return false;
    });
}, TaskContinuationOptions.OnlyOnFaulted);

task.Start();
Thread.Sleep(2000);
continuation.Wait();

注:TaskCanceledException継続がキャンセルされたために元のタスクが例外をスローしなかった場合( によりTaskContinuationOptions.OnlyOnFaulted)、それは をスローします。それを避けるには、単にフラグを削除して、t.IsFaulted.

于 2014-11-27T23:21:40.080 に答える