2015-12-21 91 views
1

考慮以下方法:如何隱藏任務任務?

private async Task<Task<Response>> SendAsync(string data) 
{ 
    this.Tcs = new TaskCompletionSource<Response>(); 

    await this.Stream.WriteAsync(...); 
    await this.Stream.FlushAsync(); 

    return this.Tcs.Task; 
} 

我有一個異步方法,我希望返回Task<Response>。但是因爲我想返回TaskCompletionSource<Response>(其他地方設置,所以我不能在這裏等待),我不得不返回Task<Task<Response>>

在調用代碼中,我有兩種方法來處理它,同時從課堂外隱藏這個醜陋。假設反應並不重要,可以忽略不計,我可以簡單地返回一個Task

public Task GetAsync(string key) 
{ 
    return this.SendAsync("GET " + key); 
} 

在另一方面,如果我想回應,我都用這個醜陋await await,使其工作:

public async Task<Response> GetAsync(string key) 
{ 
    return await await this.SendAsync("GET " + key); 
} 

是否有與此處理,即返回從SendAsync()Task<Response>不暴露Task<Task<Response>>類之外的一個更好的辦法,並在同一時間不使用await await

+1

'SendAsync',而不是'return this.Tcs.Task;'爲什麼不'返回等待這個.Tcs.Task;'乾淨'任務'返回類型? – quetzalcoatl

+0

這確實是一個奇怪的'async'方法,但是因爲您詢問了解包'Task >',這正是'Unwrap'擴展方法(在System.Threading.Tasks.TaskExtensions中定義的)所做的。 –

回答

1

我不知道爲什麼你需要使用TaskCompletionSource裏面的一個異步方法。通常你要麼做這一個或另一個。

但是,如果你必須忘記返回TaskCompletionSource.Task。只需等待任務像你這樣的異步方法(WriteAsyncFlushAsync)休息和改變方法返回Task<Response>

private async Task<Response> SendAsync(string data) 
{ 
    this.Tcs = new TaskCompletionSource<Response>(); 

    await this.Stream.WriteAsync(...); 
    await this.Stream.FlushAsync(); 

    return await this.Tcs.Task; 
} 

這樣的異步方法返回一個被完成的任務時,有一個Response所以你只需要await SendAsync("...")一次。

+0

我其實並沒有這樣做,因爲我想按原樣返回任務,而無需等待它完成。但我想對於來電者來說,這不會有什麼不同,對吧? – Gigi

+0

@Gigi。如果你的方法是異步的,那麼在方法內部等待意味着調用者返回一個代表整個異步方法的任務。您不會同步阻止該方法。當您等待WriteAsync時,任務返回給調用者。 – i3arnon

1

@ i3arnon的答案是一個很好的解決方案,但另一種解決方案是使用Unwrap擴展方法。

TaskExtensions.Unwrap方法被設計用於轉換Task<Task<TResult>>Task<TResult>,並且可以使用如下:

public Task<Response> GetAsync(string key) 
{ 
    return this.SendAsync("GET " + key).Unwrap(); 
} 

任何結果,異常或取消將被正確地傳播到所得Task<TResult>