如何隐藏任务的任务

本文关键字:任务 隐藏 何隐藏 | 更新日期: 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。只需像执行其他异步方法(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;
}

通过这种方式,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>