2016-09-20 6 views
2

私は多くのタスクが例外をスローする可能性があるタスク並列問題に取り組んでいます。Task.WhenAllで例外をスローするタスクを無視し、完了した結果のみを取得します。

正常に終了したすべてのタスクを処理し、残りのログを記録します。 Task.WaitAllは、残りの結果を収集することなく、タスクの例外を宣伝します。残りの結果を無視してExcceptionTkの例外を投げると

static readonly Task<string> NormalTask1 = Task.FromResult("Task result 1"); 
    static readonly Task<string> NormalTask2 = Task.FromResult("Task result 2"); 
    static readonly Task<string> ExceptionTk = Task.FromException<string>(new Exception("Bad Task")); 
    var results = await Task.WaitAll(new []{ NormalTask1,NormalTask2,ExceptionTk}); 

Task.Waitall。例外を無視して結果を得る方法と例外を同時にログに記録する方法はありますか?

私はtry{...}catch(){...}内部例外をタスクにラップできますが、私はそれらにアクセスできません。このオーバーヘッドを追加する必要はありません。

+0

個々のタスクのステータスを確認できます。 NormalTask​​1とNormalTask​​2がRanToCompletionで、ExceptionTkがFaultedであることがわかります。 –

+0

例外をキャッチする*のオーバーヘッドはありません。例外を頻繁に無視したい場合は、すべての結果を 'Result '型に変換して一様に扱うラッパー関数を使用できます。それは鉄道指向のプログラミングスタイルの一部です。 –

+0

@ PanagiotisKanavosオーバーヘッドはタスクのラッピングを対象としたもので、例外をキャッチするものではありません。 –

答えて

4

あなたはTask.WhenAllの代わりに使用するには、このようなメソッドを作成することができます:

public Task<ResultOrException<T>[]> WhenAllOrException<T>(IEnumerable<Task<T>> tasks) 
{  
    return Task.WhenAll(
     tasks.Select(
      task => task.ContinueWith(
       t => t.IsFaulted 
        ? new ResultOrException<T>(t.Exception) 
        : new ResultOrException<T>(t.Result)))); 
} 


public class ResultOrException<T> 
{ 
    public ResultOrException(T result) 
    { 
     IsSuccess = true; 
     Result = result; 
    } 

    public ResultOrException(Exception ex) 
    { 
     IsSuccess = false; 
     Exception = ex; 
    } 

    public bool IsSuccess { get; } 
    public T Result { get; } 
    public Exception Exception { get; } 
} 

その後、あなたはそれが成功したかどうかを確認するために、それぞれの結果を確認することができます。


EDIT:上のコードは取り消しを処理しません。

public Task<ResultOrException<T>[]> WhenAllOrException<T>(IEnumerable<Task<T>> tasks) 
{  
    return Task.WhenAll(tasks.Select(task => WrapResultOrException(task))); 
} 

private async Task<ResultOrException<T>> WrapResultOrException<T>(Task<T> task) 
{ 
    try 
    {   
     var result = await task; 
     return new ResultOrException<T>(result); 
    } 
    catch (Exception ex) 
    { 
     return new ResultOrException<T>(ex); 
    } 
} 
+0

も見てください。それは鉄道指向プログラミングにほぼ似ています。おそらく、OPは元の関数自体を変更して、結果値を返すか、またはラッパー関数を使用してすべてのタスク結果を結果<>に変換することを検討する必要があります –

+0

タスクがキャンセルされたらどうなりますか?その場合も処理したい場合は、 't.IsFaulted'を' t.Exception!= null'に置き換えてください。 – svick

+0

@svick良い点。 't.Exception'をチェックすると、キャンセルされたタスクに例外が設定されていない可能性があります(' Task.FromCanceled'でチェックされているだけです)。私の更新された答えを見てください。 –

関連する問題