如何隐藏任务任务?

时间:2015-12-21 22:26:43

标签: c# .net async-await task-parallel-library 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;
}

我有一个异步方法,我期望返回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} }}?

2 个答案:

答案 0 :(得分:1)

我不确定为什么你需要使用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("...")一次。

答案 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>