【问题标题】:How do I hide Task of Task?如何隐藏任务的任务?
【发布时间】:2015-12-22 06:47:32
【问题描述】:

考虑以下方法:

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&lt;Response&gt;。但是由于我想返回TaskCompletionSource&lt;Response&gt;(它在其他地方设置,所以我不能在这里等待它),我实际上必须返回Task&lt;Task&lt;Response&gt;&gt;

在调用代码中,我有两种处理方法,同时将这种丑陋隐藏在类的外部。假设响应不重要并且可以忽略,我可以简单地返回一个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&lt;Response&gt;而不在课堂外暴露Task&lt;Task&lt;Response&gt;&gt;,同时不使用await await

【问题讨论】:

  • SendAsync 中,而不是return this.Tcs.Task; 为什么不使用return await this.Tcs.Task; 来获得干净的Task&lt;Response&gt; 返回类型?
  • 这确实是一个看起来很奇怪的async 方法,但既然您询问了关于解开Task&lt;Task&lt;T&gt;&gt; 的问题,这正是Unwrap 扩展方法(在System.Threading.Tasks.TaskExtensions 中定义)所做的。

标签: c# .net async-await task-parallel-library task


【解决方案1】:

我不确定您为什么需要在 inside 异步方法中使用 TaskCompletionSource。通常你要么做一个,要么做另一个。

但如果你必须忘记返回TaskCompletionSource.Task。只需像执行其余异步方法(WriteAsyncFlushAsync)一样等待任务,然后将方法更改为返回 Task&lt;Response&gt;

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("...") 一次。

【讨论】:

  • 我实际上并没有这样做,因为我想按原样返回任务,而不是等待它完成。但我想对调用者来说,这不会有什么不同,对吧?
  • @Gigi 完全正确。如果您的方法无论如何都是异步的,那么在方法内部等待意味着调用者返回一个代表整个异步方法的任务。您不会同步阻止该方法。当您等待WriteAsync时,任务将返回给调用者。
【解决方案2】:

@i3arnon 的回答是一个很好的解决方案,但是另一个解决方案是使用 Unwrap 扩展方法。

TaskExtensions.Unwrap 方法旨在将Task&lt;Task&lt;TResult&gt;&gt; 转换为Task&lt;TResult&gt;,可按如下方式使用:

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

任何结果、异常或取消都将正确传播到生成的Task&lt;TResult&gt;

【讨论】:

    猜你喜欢
    • 2020-10-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-24
    • 1970-01-01
    • 1970-01-01
    • 2011-05-02
    • 1970-01-01
    相关资源
    最近更新 更多