如何处理异步函数

时间:2015-07-19 00:05:32

标签: c# asynchronous restsharp

在处理使用异步休息调用的数据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的例子?

1 个答案:

答案 0 :(得分:3)

我认为您确实需要退后一步,了解如何使用asyncawait关键字。除此之外,您还需要了解编码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"); 编程风格的文档。一旦你绕过为你完成的编译器魔法,它就会非常整洁。但如果你不花时间真正理解它的运作方式,那么它很容易迷失。