2015-07-19 56 views
2

當處理使用異步休息調用的數據API(我正在使用RestSharp.Portable)時,處理返回值的最佳方法是什麼?由於異步函數只能返回任務或任務...但調用方無法返回到返回值...... API如何將數據返回給調用方?全球屬性?如何處理異步函數中的返回值

從我目前閱讀的內容看來,回調函數是與響應數據交互的唯一方式?

以下面的方法爲例,以前我沒有使用異步休息庫,並能返回一個值,但將其轉換成使用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.Completed等處被觸發的事件?

我對這個異步概念非常模糊。有沒有寫可移植數據API的例子?

+0

我不明白這個問題。你正在設定任務的結果。這些數據將在任務完成時返回給調用者。 –

+0

不是,因爲該方法在發送client.ExecuteAsync後立即退出。而tcs.Task沒有提供與價值互動的直接方式。當我添加'await'關鍵字(強制在退出之前完成方法執行)時,我開始收到特定於RestSharp.Portable exe的編譯器錯誤,並且對我沒有多大意義。我將閱讀@sstan建議的文章,看看這些錯誤是否有意義。我可能在我的實現中丟失了一些明顯的東西。感謝您的迴應! – Robert

回答

2

我認爲你真的需要退後一步,閱讀關於如何使用asyncawait關鍵字。除此之外,編碼async方法時,您需要了解幕後發生的一些編譯器魔法。

這裏是一個很好的開始:Asynchronous Programming with Async and Await

更多你的問題,Return Types and Parameters部分有這樣一段話:

您指定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; 
} 

注意如何,儘管該方法返回類型的Task<int>,該return語句只是返回一個int,而不是Task<int>。這基本上是因爲有一些編譯器的魔法,只有在async方法中才合法。

不希望讓所有的細節,你也應該知道,async方法的調用者通常希望這樣做使用await關鍵字,它知道如何處理TaskTask<TResult>返回值,並自動解開以透明的方式爲您提供實際的預期回報值(幕後更多編譯器魔術)。

因此,對於上面的例子,這裏有一個方法來調用它:

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編程風格的文檔。一旦你圍繞着爲你完成的編譯器魔術包圍你的頭部,它就非常整齊。但如果你不花時間真正理解它的工作原理,那麼很容易迷路。

+0

感謝您閱讀該文章的鏈接。我會嘗試你的建議,看看我能否理解這一切。 – Robert