2013-01-25 153 views
1

我正在開發一個包裝REST風格的Web服務的類庫(供其他開發人員使用)。我使用System.Net.Http名稱空間中的HttpClient類型異步執行所有API調用。我應該公開異步方法嗎?

除了簡單地發送/接收內容,我還想對返回的XML數據進行額外的處理。無論你如何放置它,都需要在類庫中的某處使用Async/Await關鍵字。

我的問題是,揭示使用Async關鍵字的方法以及爲什麼是好的或壞主意。我讀過某處應該讓Async方法爲private,然後用一個return語句創建一個額外的方法。這就是我一直在做的事情,但這並不正確。

Public Function InvokeAsync(command As HttpRequestMessage) As Task(Of CommandResult) 
    Return InvokeAsyncInternal(command) 
End Function 

Private Async Function InvokeAsyncInternal(command As HttpRequestMessage) As Task(Of CommandResult) 
    Dim rawCommandResult As HttpResponseMessage = Await myHttpClient.SendAsync(command) 
    Dim finalResult As CommandResult = AdditionalProcessing(rawCommandResult) 
    Return finalResult 
End Function 

請記住,這是一個過於簡單的代碼示例:是否有任何好的參數不要直接暴露Async方法?

+0

「我讀過的地方......」你在哪裏讀到的?你有鏈接嗎?總的來說,我認爲你不應該因爲有人這樣說而做某件事。你應該這樣做,因爲他們的論點是有道理的,你同意它。 – svick

+0

這是在互聯網上的許多「異步/等待」博客文章之一。這在當時是有道理的,但現在我開始重新考慮,因爲它似乎沒有增加任何價值。 –

回答

3

這與編譯器轉換有關;您可以將「真實」Async方法與其對應的Public分開,並且您可以獲得與爲迭代器(Yield)方法執行相同種類分離時相同的好處。

特別是,從包裝器拋出的異常處理方式與從Async方法拋出的異常處理方式不同。當返回TaskAsync方法拋出Exception時,它將放置在返回的Task上,而不是直接發送給調用方。當Public包裝方法(不是Async)引發Exception時,它直接拋出給調用者。

因此,前提條件式檢查可以放在Public方法中。調用者可以忽略Task上的異常,但它們不能忽略直接拋出的異常。將前置條件異常放在Public包裝器中會強制調用者意識到他們濫用API,並且還允許將運行時異常(位於Task上)的使用異常(直接拋出)與用法異常分開。

如果你的方法沒有先決條件,那麼你的Public包裝只是返回內部Task。在這種情況下,Public包裝是不必要的。

+0

因此,只包裝我的方法,以避免暴露與「Async」或「Iterator」關鍵字的方法是完全沒有意義的?錯誤的輸入由Web服務正確處理,所以我不必擔心驗證。 –

+0

這並非毫無意義,有時它是必要的。例如,當您在應用程序的第一部分拋出異常時,除非您等待該功能,否則不會自然獲得該異常。 –

+0

@ToniPetrina但包裝的方法並沒有做任何事情。它不會影響如何表示異常。 – svick

0

考慮以下情形:

void Caller() 
{ 
    var t = AsyncThatThrows(null); 
    // ... 
    Task.WaitAny(t, t2); // <-- exception thrown here 
} 

Task AsyncThatThrows(Object o) 
{ 
    if (o == null) 
     throw new ArgumentNullException("o"); 

    // ... 
    await // ... 
    // ... 
} 

注意,異常之前拋出第一的await,但例外僅在檢查任務重新拋出。無論是通過等待還是獲得結果。如果你選擇來實現它的方式如下:

void Caller() 
{ 
    var t = AsyncThatThrows(null);// <-- exception thrown here 
    // ... 
    Task.WaitAny(t, t2); 
} 

Task AsyncThatThrows(Object o) 
{ 
    if (o == null) 
     throw new ArgumentNullException("o"); 

    return AsyncThatThrows_Impl(o); 
} 

Task AsyncThatThrows_Impl(Object o) 
{ 
    // ... 
    await // ... 
    // ... 
} 

現在異常可以在其調用被抓,你沒有檢查的任務。在前一種情況下,儘管我們還沒有開始異步部件,但異常仍將存儲在生成的任務中。

+0

對於不知道編譯器做什麼的人來說,這個東西是非常難以理解的 –

相關問題