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