让我们假设我正在包装一个复杂的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 A
在Call B
开始之前完成,并在Call C
开始之前完成。这否定了异步代码的全部要点。
我的假设是准确的,还是我遗漏了某些东西,如果我遗失了什么东西呢?
如果我没有遗漏某些内容,我如何延迟或任务化(我确定它是一句话)将结果转换为我的结果类型?
实际考虑因素
真正的方法有时会调用底层的api,有时会做其他事情。 底层api返回的对象是一个没有公共构造函数的具体类型,所以我不能创建一个并返回它。
答案 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);