考虑以下方法:
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);
}
有没有更好的方法来解决这个问题,即从Task<Response>
返回SendAsync()
而不在课堂外暴露Task<Task<Response>>
,同时不使用{{1} }}?
答案 0 :(得分:1)
我不确定为什么你需要使用TaskCompletionSource
内部异步方法。通常你要么做其中一个。
但如果你必须忘记归还TaskCompletionSource.Task
。只需等待任务,就像执行其余的异步方法(WriteAsync
和FlushAsync
)一样,并将方法更改为返回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;
}
这样,async方法会返回一个任务,当Response
时,该任务就会完成,因此您只需要await SendAsync("...")
一次。
答案 1 :(得分:1)
@ i3arnon的答案是一个很好的解决方案,但另一个解决方案是使用Unwrap
扩展方法。
TaskExtensions.Unwrap
方法用于将Task<Task<TResult>>
转换为Task<TResult>
,可按以下方式使用:
public Task<Response> GetAsync(string key)
{
return this.SendAsync("GET " + key).Unwrap();
}
任何结果,异常或取消都会正确传播到生成的Task<TResult>
。