如何延迟异步方法结果的转换?

时间:2016-04-25 16:00:40

标签: c# async-await

让我们假设我正在包装一个复杂的API,并且我有自己的结果类型,我想从包装底层异步方法的异步方法中返回。

interface IMyWrapper
{
    Task<MyResult> GetResultAsync(string arg);
}

显而易见的方法是等待底层调用的结果,转换结果并将其传回去

class MyWrapper: IMyWrapper
{
    private IUnderlyingObject theirObject;
    public async Task<MyResult> GetResultAsync(string arg)
    {
        var theirResult = await theirObject.GetResultAsync(arg);
        return new MyResult(theirResult);
    }
}

假设我使用MyWrapper的客户端代码。 。

var wrapper = new MyWrapper();

var taskA = wrapper.GetResultAsync("A"); // Call A
var taskB = wrapper.GetResultAsync("B"); // Call B

var apiTask = someApi.DoTheThingAsync(); // Call C

var api = await apiTask;
var a = await taskA;
var b = await taskB;

DoSomethingElse(api, a, b); . . .

我假设Call ACall B开始之前完成,并在Call C开始之前完成。这否定了异步代码的全部要点。

我的假设是准确的,还是我遗漏了某些东西,如果我遗失了什么东西呢?

如果我没有遗漏某些内容,我如何延迟或任务化(我确定它是一句话)将结果转换为我的结果类型?

实际考虑因素

真正的方法有时会调用底层的api,有时会做其他事情。 底层api返回的对象是一个没有公共构造函数的具体类型,所以我不能创建一个并返回它。

4 个答案:

答案 0 :(得分:3)

  

我假设呼叫A在呼叫B启动之前完成,并且在呼叫C启动之前完成。

这个假设是不正确的。在呼叫B开始之前呼叫A 可以完成,如果它快速完成 ,但没有强制它,所以它几乎肯定不会。

  

我的假设是准确的,还是我遗漏了某些东西,如果我遗失了什么东西呢?

您似乎错过了当您调用异步方法时,它必然会在返回时完成。 async方法的整个是它在实际工作完成之前返回,并且工作在将来的某个时刻完成。连续调用几个异步方法不会在下一次启动之前强制第一个完成;这只适用于同步代码。

答案 1 :(得分:2)

不,你的假设是错误的。任务B(甚至任务C)可以在任务A完成之前启动,并且可以按任何顺序完成。唯一可以保证的是&#34; DoSomethingElse&#34;将在所有任务完成后调用。

答案 2 :(得分:0)

在上面的代码中,首先要完成的是Call C,然后是Call A,最后是Call B.

var api = await apiTask; // Call C
var a = await taskA; // Call A
var b = await taskB; // Call B

答案 3 :(得分:-1)

为了等待您需要使用的所有任务 TaskWhenAll

await Task.WhenAll(apiTask,taskA,taskB);

//All tasks have been completed and it's safe to access the result.
DoSomethingEsle(apiTask.Result, taskA.Result, taskB.Result);