如何隐藏任务的任务?
How do I hide Task of Task?
考虑以下方法:
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;
}
我有一个异步方法,我希望它 return Task<Response>
。但是因为我想 return TaskCompletionSource<Response>
(在别处设置,所以我不能在这里等待),我实际上必须 return Task<Task<Response>>
代替。
在调用代码中,我有两种处理方法,同时从 class 外部隐藏这种丑陋之处。假设响应不重要并且可以忽略,我可以简单地 return a 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);
}
有没有更好的方法来处理这个问题,即 return 从 SendAsync()
中获取 Task<Response>
,而不在 class 之外暴露 Task<Task<Response>>
,同时不使用 await await
?
我不确定您为什么需要在 TaskCompletionSource
异步方法中使用。通常你要么做一个,要么做另一个。
但是如果你必须忘记 returning TaskCompletionSource.Task
。只需像执行其余异步方法(WriteAsync
和 FlushAsync
)一样等待任务并将方法更改为 return 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;
}
这样,异步方法 return 是一个在有 Response
时完成的任务,因此您只需要 await SendAsync("...")
一次。
@i3arnon 的回答是一个很好的解决方案,但是另一种解决方案是使用 Unwrap
扩展方法。
TaskExtensions.Unwrap
方法专为将 Task<Task<TResult>>
转换为 Task<TResult>
而设计,可按如下方式使用:
public Task<Response> GetAsync(string key)
{
return this.SendAsync("GET " + key).Unwrap();
}
任何结果、异常或取消都将正确传播到结果 Task<TResult>
。
考虑以下方法:
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;
}
我有一个异步方法,我希望它 return Task<Response>
。但是因为我想 return TaskCompletionSource<Response>
(在别处设置,所以我不能在这里等待),我实际上必须 return Task<Task<Response>>
代替。
在调用代码中,我有两种处理方法,同时从 class 外部隐藏这种丑陋之处。假设响应不重要并且可以忽略,我可以简单地 return a 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);
}
有没有更好的方法来处理这个问题,即 return 从 SendAsync()
中获取 Task<Response>
,而不在 class 之外暴露 Task<Task<Response>>
,同时不使用 await await
?
我不确定您为什么需要在 TaskCompletionSource
异步方法中使用。通常你要么做一个,要么做另一个。
但是如果你必须忘记 returning TaskCompletionSource.Task
。只需像执行其余异步方法(WriteAsync
和 FlushAsync
)一样等待任务并将方法更改为 return 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;
}
这样,异步方法 return 是一个在有 Response
时完成的任务,因此您只需要 await SendAsync("...")
一次。
@i3arnon 的回答是一个很好的解决方案,但是另一种解决方案是使用 Unwrap
扩展方法。
TaskExtensions.Unwrap
方法专为将 Task<Task<TResult>>
转换为 Task<TResult>
而设计,可按如下方式使用:
public Task<Response> GetAsync(string key)
{
return this.SendAsync("GET " + key).Unwrap();
}
任何结果、异常或取消都将正确传播到结果 Task<TResult>
。