如何隐藏任务的任务
本文关键字:任务 隐藏 何隐藏 | 更新日期: 2023-09-27 18:27:36
考虑以下方法:
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
?
我不知道为什么需要在异步方法中使用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("...")
一次。
@iArnon的答案是一个很好的解决方案,但另一个解决方案是使用Unwrap
扩展方法。
TaskExtensions.Unwrap
方法被设计用于将Task<Task<TResult>>
转换为Task<TResult>
,并且可以如下使用:
public Task<Response> GetAsync(string key)
{
return this.SendAsync("GET " + key).Unwrap();
}
任何结果、异常或取消都将正确地传播到生成的Task<TResult>
。