web-dev-qa-db-ja.com

タスクが例外をキャンセルしました(ThrowForNonSuccess)

これは、この質問の続きです: 複数のタスクの継続

回答のようにコードを変更しましたが、タスクを実行しようとするとTaskCancelledExceptionsを受け取ります。

_public virtual async Task RunAsync(TaskWithProgress task)
{
    Show();
    TaskIsRunning();
    await SetCompletedHandler(TaskComplete());
    await SetCancelledHandler(TaskCancelled())
    await SetFaultedHandler(TaskFaulted());
    await task;
    Close();
}
_

ただし、次のコードはそうではありません。私はその理由について少し立ち往生しています。

_public virtual Task RunAsync(TaskWithProgress task)
{
    Show();
    TaskIsRunning();
    SetCompletedHandler(TaskComplete());
    SetCancelledHandler(TaskCancelled())
    SetFaultedHandler(TaskFaulted());
    return task;
}
_

呼び出しコードには、基本的に次のものが含まれます。

_await progressDialog.RunAsync(task);
_

編集:

cancellationtokenをどこでもキャンセルしないので、なぜこれがその例外をスローしているのかわかりません。

3つのSetXXXHandler()メソッドは、基本的に、継続ステータスが異なる次のコードを実行します。

_task.ContinueWith(_ => action(), CancellationToken.None, TaskContinuationOptions.OnlyOnCanceled, this.Scheduler);
_

スタックトレースはここにあります:

_   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at FugroDXExt.frmBaseProgressAsync.<RunAsync>d__7.MoveNext() in d:\C#\FugroDXExt\trunk\frmBaseProgressAsync.cs:line 92
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at FCP.Forms.frmProcessing.<mnuApplyCenteredSmoothing_ItemClick>d__34.MoveNext() in d:\C#\FCP\FCP\Forms\frmProcessing.cs:line 578
_

Close()は単にフォームを閉じます。その行を削除すると、同じことが起こります。

8
Simon

SetCancelledHandlerはタスクに継続を追加するだけだとあなたは言います。 RunAsyncがパラメーターとして取得するのと同じタスクだと思いますが、コードではSetCancelledHandlerがタスクを続行する方法を知ることはできません(コードが欠落していると思います)。いずれかの方法...

タスクが完了し、キャンセルされ、障害が発生したときに実行されるタスクに3つの継続を登録します。ここで、元のタスクがキャンセルされずに正常に完了したと仮定します。つまり、継続の2つ(OnCanceledOnFaulted)は、実行する必要がないため実行されません。 TPLで実行しないようにタスクに指示する方法は、タスクをキャンセルすることです。これは自動的に行われます。

2つのコードスニペットの違いは、最初のコードスニペットではタスクの継続をawaitし、それらがキャンセルされて例外を説明することです。 2番目のスニペットでは、継続を待つのではなく、正常に実行されて完了した元のタスクだけを待ちます。

追伸:2番目のオプションの方が適切だと思います。これらすべての継続をawaitする必要はありません。必要に応じて、実行させたいと考えています。

TL; DR:キャンセルされた継続タスクをawaitします。元のタスクではなく、継続タスクが例外をスローします。

10
i3arnon