2014-03-25 41 views
10

我的理解是,return Task.FromResult(foo)是一個簡單的簡寫:有沒有簡單的方法來返回一個異常的任務?

var tcs = new TaskCompletionSource<TFoo>(); 
tcs.SetResult(foo); 
return tcs.Task; 

有一些等效返回異常狀態的任務?

var tcs = new TaskCompletionSource<TFoo>(); 
tcs.SetException(new NotSupportedException()); // or whatever is appropriate 
return tcs.Task; 

我沒有看到像Task.FromException東西。或者,在不返回任務的情況下拋出異常更合適?

+1

看着你的代碼讓我想要選擇它並在ReSharper中使用「提取方法」。 –

+1

看來,這種方法是故意不暴露的:它存在,但是「內部」。 – dlev

+0

該方法的問題在於,您返回的異常不會有堆棧跟蹤,因爲它實際上不會被拋出。也許這就是爲什麼FromException沒有公開。 –

回答

11

我的理解是,返回Task.FromResult(foo)是一個簡單的 ... [TaskCompletionSource.SetResult]的簡寫。

其實,Task.FromResult不使用TaskCompletionSourceits implementation比簡單得多。

對於返回異常狀態的任務是否存在一些等價物?

我估計TaskCompletionSource將是最好的選擇。你也可以做這樣的事情:

static Task FromExAsync(Exception ex) 
{ 
    var task = new Task(() => { throw ex; }); 
    task.RunSynchronously(); 
    return task; 
} 

的異常不會返回task外面傳播,直到通過await tasktask.Wait(),這應該是一個期望的行爲觀察。

請注意,如果傳遞給FromExAsync的異常是活動異常(即已被拋出並被捕獲到其他地方),那麼重新拋出它會丟失當前堆棧跟蹤和Watson存儲區異常中存儲的信息。有兩種處理方式:

  • AggregateException包裝例外。這將提供原始異常爲AggregateException.InnerException

static Task FromExAsync(Exception ex) 
{ 
    var task = new Task(() => { throw new AggregateException(ex); }); 
    task.RunSynchronously(); 
    return task; 
} 
  • 使用ExceptionDispatchInfo.Capture流活動異常的狀態:

static Task FromExAsync(Exception ex) 
{ 
    var ei = System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(ex); 
    var task = new Task(() => { ei.Throw(); }); 
    task.RunSynchronously(); 
    return task; 
} 

最後,也許最簡單但最糟糕的選擇(由於overhead of the state machine和編譯器警告)是從async方法拋出:

static async Task FromExAsync(Exception ex) 
{ 
    throw ex; 
} 
+0

鑑於這種討論的開銷,也許可以考慮使用自定義的Awaiter? – Aron

+1

@Aron,我沒有看到一個自定義的awaiter如何消除'async'和任務機器,因爲@MattJohnson需要一個Task對象作爲返回值。有關其他詳細信息,請選中[this](http://stackoverflow.com/q/22268569/1768303)。 – Noseratio

+1

謝謝。異步編程非常強大,但有時甚至最小的東西都會讓人困惑。 –

相關問題