如何处理异步函数中的返回值
在处理使用异步rest调用的数据API时(我使用的是RestSharp.Portable),处理返回值的最佳方法是什么? 由于异步函数只能返回任务或任务…但调用者无法返回返回值… API如何将数据返回给调用者? 全球物业?
从我到目前为止所看到的,似乎回调函数是与Response Data交互的唯一方法?
以下面的方法为例; 以前我没有使用异步Rest库并且能够返回一个值但是在将其转换为使用RestSharp.Portable后,我没有看到返回值的方法:
public async Task GetEntityDescriptor(string entityType) { TaskCompletionSource tcs = new TaskCompletionSource(); var req = new RestRequest("/qcbin/rest/domains/{domain}/projects/{project}/customization/entities/{entityType}"); AddDomainAndProject(req); req.AddParameter("entityType", entityType, ParameterType.UrlSegment); client.ExecuteAsync(req, (res) => { if (res.ResponseStatus == ResponseStatus.Error) { tcs.TrySetException(res.ErrorException); } else { tcs.SetResult(res.Data); } } ); return tcs.Task; }
我所能做的就是返回Task,但是调用者仍无法获取响应数据,或者我错过了一些明显的东西? 调用者是否可以订阅在Task.Completed等处被触发的事件?
我对这个异步概念非常模糊。 是否有编写可移植数据API的示例?
我认为你真的需要退后一步,阅读有关如何使用async
和await
关键字的信息。 除此之外,您还需要了解编码async
方法时幕后发生的一些编译器魔法。
这是一个很好的起点: 使用Async和Await进行异步编程 。
更多问题, 返回类型和参数部分有这样的说法:
如果方法包含指定TResult类型的操作数的
Return
(Visual Basic)或return
(C#)语句,则指定Task
作为返回类型。
然后给出以下代码示例:
// Signature specifies Task async Task TaskOfTResult_MethodAsync() { int hours; // . . . // Return statement specifies an integer result. return hours; }
请注意,尽管返回类型为Task
,但return
语句只返回一个int
,而不是一个Task
。 这基本上是因为有一些编译器魔法正在进行,这使得这只在async
方法中合法。
在不想了解所有细节的情况下,您还应该知道async
方法的调用者通常希望使用await
关键字,它知道如何处理Task
或Task
返回值并自动解包以透明的方式为您提供实际预期的返回值(幕后更多的编译魔术)。
所以对于上面的例子,这里有一种方法来调用它:
int intValue = await TaskOfTResult_MethodAsync(); // Task is automatically unwrapped to an int by the await keyword when the async method completes.
或者,如果您希望启动异步方法,在此期间执行其他一些工作,然后等待异步方法完成,可以这样做:
Task t = TaskOfTResult_MethodAsync(); // perform other work here int intValue = await t; // wait for TaskOfTResult_MethodAsync to complete before continuing.
希望这能让您大致了解如何从异步方法传递值。
对于您的具体示例,我不熟悉RestSharp(从未使用过它)。 但是从我读的很少,我想你会想要使用client.ExecuteTaskAsync
而不是client.ExecuteAsync
来更好地适应async-await
模型。
我在想你的方法看起来像这样:
public async Task GetEntityDescriptor(string entityType) { var req = new RestRequest("/qcbin/rest/domains/{domain}/projects/{project}/customization/entities/{entityType}"); AddDomainAndProject(req); req.AddParameter("entityType", entityType, ParameterType.UrlSegment); var res = await client.ExecuteTaskAsync (req); if (res.ResponseStatus == ResponseStatus.Error) { throw new Exception("rethrowing", res.ErrorException); } else { return res.Data; } }
您的调用代码将如下所示:
EntityResourceDescriptor erd = await GetEntityDescriptor("entityType");
我希望你设法让这个工作。 但同样,请务必阅读有关async-await
编程风格的文档。 一旦你围绕为你完成的编译器魔法包裹你的头部,它就非常整洁。 但如果你没有花时间真正理解它是如何工作的,那么它很容易迷失。