如何处理异步函数中的返回值

Rob*_*ert 2 c# asynchronous restsharp

在处理使用异步 rest 调用的数据 API 时(我使用的是 RestSharp.Portable),处理返回值的最佳方法是什么?由于 async 函数只能返回一个 Task 或 Task ......但调用者无法返回返回值...... API如何将数据返回给调用者?全局属性?

从我到目前为止所读到的内容来看,回调函数似乎是与响应数据交互的唯一方法?

以下面的方法为例;以前我没有使用异步 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;
    }
Run Code Online (Sandbox Code Playgroud)

在这里我所能做的就是返回 Task 但调用者仍然无法获取响应数据,或者我是否遗漏了一些明显的东西?调用者可以订阅在 Task.Completed 等处触发的事件吗?

我对这个异步概念非常模糊。是否有编写可移植数据 API 的示例?

sst*_*tan 5

我认为您真的需要退后一步阅读有关如何使用asyncawait关键字的信息。除其他事项外,您需要了解编码async方法时在幕后发生的一些编译器魔术。

这是一个很好的起点:使用 Async 和 Await 进行异步编程

更多关于您的问题,返回类型和参数部分有这样的说法:

您指定Task<TResult>的返回类型,如果该方法中包含一个Return(Visual Basic)或return(C#)语句,指定类型的操作数TResult

然后给出以下代码示例:

// Signature specifies Task<TResult>
async Task<int> TaskOfTResult_MethodAsync()
{
    int hours;
    // . . .
    // Return statement specifies an integer result.
    return hours;
}
Run Code Online (Sandbox Code Playgroud)

请注意,尽管方法返回类型为Task<int>,但该return语句仅返回一个int,而不是一个Task<int>。这基本上是因为有一些编译器魔法正在进行,这使得这仅在async方法中合法。

不想深入了解所有细节,您还应该知道async方法的调用者通常会使用await关键字来这样做,该关键字知道如何处理TaskorTask<TResult>返回值并自动为您解开实际的预期返回值一种透明的方式(幕后更多的编译器魔法)。

所以对于上面的例子,这里是一种调用方式:

int intValue = await TaskOfTResult_MethodAsync(); // Task<int> is automatically unwrapped to an int by the await keyword when the async method completes.
Run Code Online (Sandbox Code Playgroud)

或者,如果您希望启动异步方法,在此期间执行一些其他工作,然后等待异步方法完成,可以这样做:

Task<int> t = TaskOfTResult_MethodAsync();
// perform other work here
int intValue = await t; // wait for TaskOfTResult_MethodAsync to complete before continuing.
Run Code Online (Sandbox Code Playgroud)

希望这能让您大致了解如何从异步方法传回值。

对于您的具体示例,我不熟悉 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

您的调用代码将如下所示:

EntityResourceDescriptor erd = await GetEntityDescriptor("entityType");
Run Code Online (Sandbox Code Playgroud)

我希望你设法让这个工作。但同样,请务必阅读有关async-await编程风格的文档。一旦您将头脑围绕为您完成的编译器魔术,它就非常整洁。但是,如果您不花时间真正了解它的工作原理,就很容易迷路。