如何处理异步函数中的 return 值
How to handle return values in async function
在处理使用异步休息调用的数据 API 时(我正在使用 RestSharp.Portable),处理 return 值的最佳方法是什么?由于异步函数只能 return 一个 Task 或 Task ...但是调用者无法返回到 return 值 ... API return 怎么会数据返回给调用者?全局属性?
从我目前所读的内容来看,回调函数似乎是与响应数据交互的唯一方式?
以下面的方法为例;以前我没有使用异步 Rest 库并且能够 return 一个值但是在将它转换为使用 RestSharp.Portable 之后,我看不到 return 值的方法:
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;
}
这里我所能做的就是 return 任务,但是调用者仍然无法获取响应数据,或者我是否遗漏了一些明显的东西?调用者可以订阅在 Task.Completed 等时触发的事件吗?
我对这个异步概念很模糊。有写Portable data API的例子吗?
我认为您确实需要退后一步,阅读有关如何使用 async
和 await
关键字的信息。除其他事项外,您还需要了解编码 async
方法时在幕后发生的一些编译器魔法。
这里是一个很好的起点:Asynchronous Programming with Async and Await。
关于你的问题,Return Types and Parameters 部分是这样说的:
You specify Task<TResult>
as the return type if the method contains a Return
(Visual Basic) or return
(C#) statement that specifies an operand of type TResult.
然后给出如下代码示例:
// Signature specifies Task<TResult>
async Task<int> TaskOfTResult_MethodAsync()
{
int hours;
// . . .
// Return statement specifies an integer result.
return hours;
}
请注意,尽管方法 return 类型为 Task<int>
,但 return
语句只是 return 一个 int
,而不是 Task<int>
.这基本上是因为有一些编译器魔术正在进行,使得这只在 async
方法中合法。
不想深入了解所有细节,您还应该知道 async
方法的调用者通常希望使用 await
关键字来调用,它知道如何处理Task
或 Task<TResult>
return 值并以透明的方式自动为您解包实际预期的 return 值(幕后有更多编译器魔法)。
所以对于上面的例子,这里有一种调用方式:
int intValue = await TaskOfTResult_MethodAsync(); // Task<int> is automatically unwrapped to an int by the await keyword when the async method completes.
或者,如果您希望启动异步方法,同时执行一些其他工作,然后等待异步方法完成,可以这样做:
Task<int> t = TaskOfTResult_MethodAsync();
// perform other work here
int intValue = await t; // wait for TaskOfTResult_MethodAsync to complete before continuing.
希望这能让您大致了解如何从异步方法传回值。
对于您的具体示例,我不熟悉 RestSharp(从未使用过)。但是从我阅读的内容来看,我认为你会想要使用 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");
我希望你能成功。但同样,请务必阅读有关 async-await
编程风格的文档。一旦您全神贯注于为您完成的编译器魔术,它就会非常整洁。但是,如果您不花时间真正了解其工作原理,很容易迷路。
在处理使用异步休息调用的数据 API 时(我正在使用 RestSharp.Portable),处理 return 值的最佳方法是什么?由于异步函数只能 return 一个 Task 或 Task ...但是调用者无法返回到 return 值 ... API return 怎么会数据返回给调用者?全局属性?
从我目前所读的内容来看,回调函数似乎是与响应数据交互的唯一方式?
以下面的方法为例;以前我没有使用异步 Rest 库并且能够 return 一个值但是在将它转换为使用 RestSharp.Portable 之后,我看不到 return 值的方法:
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;
}
这里我所能做的就是 return 任务,但是调用者仍然无法获取响应数据,或者我是否遗漏了一些明显的东西?调用者可以订阅在 Task.Completed 等时触发的事件吗?
我对这个异步概念很模糊。有写Portable data API的例子吗?
我认为您确实需要退后一步,阅读有关如何使用 async
和 await
关键字的信息。除其他事项外,您还需要了解编码 async
方法时在幕后发生的一些编译器魔法。
这里是一个很好的起点:Asynchronous Programming with Async and Await。
关于你的问题,Return Types and Parameters 部分是这样说的:
You specify
Task<TResult>
as the return type if the method contains aReturn
(Visual Basic) orreturn
(C#) statement that specifies an operand of type TResult.
然后给出如下代码示例:
// Signature specifies Task<TResult>
async Task<int> TaskOfTResult_MethodAsync()
{
int hours;
// . . .
// Return statement specifies an integer result.
return hours;
}
请注意,尽管方法 return 类型为 Task<int>
,但 return
语句只是 return 一个 int
,而不是 Task<int>
.这基本上是因为有一些编译器魔术正在进行,使得这只在 async
方法中合法。
不想深入了解所有细节,您还应该知道 async
方法的调用者通常希望使用 await
关键字来调用,它知道如何处理Task
或 Task<TResult>
return 值并以透明的方式自动为您解包实际预期的 return 值(幕后有更多编译器魔法)。
所以对于上面的例子,这里有一种调用方式:
int intValue = await TaskOfTResult_MethodAsync(); // Task<int> is automatically unwrapped to an int by the await keyword when the async method completes.
或者,如果您希望启动异步方法,同时执行一些其他工作,然后等待异步方法完成,可以这样做:
Task<int> t = TaskOfTResult_MethodAsync();
// perform other work here
int intValue = await t; // wait for TaskOfTResult_MethodAsync to complete before continuing.
希望这能让您大致了解如何从异步方法传回值。
对于您的具体示例,我不熟悉 RestSharp(从未使用过)。但是从我阅读的内容来看,我认为你会想要使用 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");
我希望你能成功。但同样,请务必阅读有关 async-await
编程风格的文档。一旦您全神贯注于为您完成的编译器魔术,它就会非常整洁。但是,如果您不花时间真正了解其工作原理,很容易迷路。