2011-08-11 10 views
6

私は、開始後に頻繁にキャンセルする必要のある短い非同期タスクを持っています。 "タスク"クラスには、IsCanceledインジケータがあり、非同期タスクが完了するまでにキャンセルされたことを示すのに便利だと思いますが、非同期タスクをキャンセル済みとしてマークする唯一の方法はわかりますasync関数にTaskCanceledExceptionをスローします。例外的に例外をスローすると、例外的に発生する状況を示すために、例外が使用されるべきであると理解する方法に反します。頻繁に起こることが予想されるときに非同期タスクをキャンセルすることを示す良い方法を誰かが知っていますか? C#async CTP - 非同期タスクをキャンセルしたとしてマークするには、TaskCanceledExceptionをスローしないでください。

class MightBeCanceled<T> 
{ 
    public readonly T Value; 
    public readonly bool IsCanceled; 

    public MightBeCanceled(T value) { Value = value; IsCanceled = false; } 
    public static MightBeCanceled<T> Canceled = new MightBeCanceled<T>(default(T), true); 
    private MightBeCanceled(T value, bool isCanceled) { Value = value; IsCanceled = isCanceled; } 
} 

... 

static async Task<MightBeCanceled<int>> Foo() 
{ 
    if (someCancellationCondition) 
     return MightBeCanceled<int>.Canceled; 
    else 
     return new MightBeCanceled<int>(42); 
} 

static async void Bar() 
{ 
    var mightBeCanceled = await Foo(); 

    if (mightBeCanceled.IsCanceled) 
     ; // Take canceled action 
    else 
     ; // Take normal action 
} 

しかし、これはそう(私はいくつかの良いコーディングとスタイルここでは簡潔にするためプラクティスを無視してきました):

私の次善の選択肢は、それが自分のIsCanceled財産のしている構造を返すことです冗長で使いにくい言うまでもなく、IsCanceledが2つ(タスクに1つ、MightBeCanceledに1つ)あるため、整合性の問題が発生します。

+1

誰がFooをキャンセルしていますか?それは、CancellationTokenを使用して、呼び出し元によってのみ取り消すことができます。 –

答えて

2

問題は、あなたがそれを待つことを選択するまで、例外が観察されないことです。したがって、awaitを呼び出す行為は、最終的な値が返されたとき、またはタスクが完了するのを待っているときに、最終的に例外を観察することを意味します。しかし、あなたが気にしない(それは火であり、仕事を忘れる)場合、例外は(ほとんどの場合)問題ではありません。

私はあまりにも奇妙なことに、集計例外を処理するためのタスクを常に実行しなければならないことがあります。しかし、少し考えてみてください。

try 
{ 
    var myResult = await Foo(); 

    // Do Success Actions Here... 
} 
catch(AggregateException e) 
{ 
    e.Flatten().Handle(ex => 
     { 
      if(ex is OperationCanceledException) 
      { 
       // Do Canceled Thing Here 
       return true; 
      } 

      return false; 
     }); 
} 

それほど遠くないです。多くの点で、私は別の仕事をキャンセルすると思います。どうすればいいですか? ThreadAbortException?それは今のところキャンセルされたようで、取り消し時に特定の例外を投げるだけではないようです。

これは、取り消しの処理方法が複数の場所で主張されているのとほぼ同じパターンです。

2

通常、キャンセルの目的は、非同期アクションの呼び出し側が処理を停止する必要があることをアクションに伝えることです。このためには、CancellationTokenを非同期メソッドに渡します。 IsCancelledが自分自身をスローするように設定するTaskを待っている理由です。それは、外部から誘発された行動への例外的なシグナルを意味しています。タスクのキャンセルは、制御フローに使用するのではなく、待機中のパーティが結果を望んでいないことを通知した場合に、非同期アクションを早期に終了するオプションを与えるだけです。

非同期アクションが内部的にキャンセルされた場合は、既にコンセプトがオーバーロードされています。その相違を反映する価値があり、提案コンテナと同様の結果コンテナのプロパティである必要があります。しかし、MightBeCancelled<T>と呼ぶのではなく、キャンセルコンセプトの違いを反映するために、おそらくInternallyCancellableResult<T>のようなものです。

関連する問題