2

例外をスローせずに実行される次のコードがあります。

        var t = Task.Factory.StartNew(() => LongRunningMethod(cancellationToken, progress), cancellationToken);
        t.ContinueWith(Callback, TaskScheduler.FromCurrentSynchronizationContext());

'LongRunningMethod'内で、cancellationToken.ThrowIfCancellationRequested()を呼び出します。コールバックは常に呼び出され(これは私が望むものです)、コールバックに正しく渡されるタスクでは、IsCancelledがtrueまたはfalseに設定されています。

async / awaitキーワードを使用して、上記の行を次のように変更する必要があります。

        try
        {
            await Task.Factory.StartNew(() => LongRunningMethod(cancellationToken, progress), cancellationToken);
            textEdit1.Text =  "Done";
        }
        catch (OperationCanceledException)
        {
            textEdit1.Text = "Cancelled";
        }

この場合、なぜThrowIfCancellationRequested()がキャッチする必要のある実際の例外をスローするのですか?

4

2 に答える 2

2

asyncは、非同期コードをより簡単にし、可能な限り同等の同期コードに近づけるように設計されました。

まず、常に例外がスローされることに注意してください。キャンセルが要求された場合、 ThrowIfCancellationRequested(驚き)例外がスローされます。

既存のコードでは、この例外はキャッチされ、Task( でラップされたAggregateException) に配置されます。は、Taskこの状態を「キャンセルされた」と解釈します。次に、継続でブールフラグを確認できます。

ただし、同等の同期コードを検討してください。

try
{
  LongRunningMethod(cancellationToken, progress);
}
catch (OperationCanceledException)
{
}

asyncそして、それはアプローチによく似ています。を使用ContinueWithしても、スローされてキャッチされる例外がまだあります。論理的には、try/を実行していますcatch。個人的には、次の理由から明示的なtry/を好みます。catch

  • 意図がより明確になるため、コードが読みやすく、維持しやすくなります。
  • コードはよりアクセスしやすくなります (大多数の C# プログラマーはtry/を理解catchしていますが、比較的少数のプログラマーは理解していますContinueWith)。

ただし、ContinueWith(わずかに)より効率的です。

于 2012-08-16T19:08:26.947 に答える
2

では、以前に実行されContinueWithた が与えられ、Taskキャンセルされたかどうかを確認できます ( Task.IsCancelled)。ではawait、それはありません。キャンセルを伝える唯一の方法は、例外を使用することです。

現在、awaitは単純にタスクを使用しているため、継続に「割り込む」ことができます。例えば:

await Task.Factory
  .StartNew(() => LongRunningMethod(cancellationToken, progress), cancellationToken)
  .ContinueWith(t=>Trace.WriteLine("Canceled"), TaskContinuationOptions.OnlyOnCanceled);

引き続き await を使用してから、キャンセル シナリオのみContinueWithを処理するために使用できます。だから、技術的には続きを待っています。await

于 2012-08-16T13:35:30.103 に答える