2009-10-12 70 views
1

如何使用F#的內置支持異步操作類暴露Event-based Asynchronous PatternWebClient類?使用F#的內置異步支持與* Async()方法

let Download(url : Uri) = 
    let client = new WebClient() 
    let html = client.DownloadString(url) 
    html 

當我試圖改變這個使用「let!」在異步

let Download(url : Uri) = 
    async { 
    let client = new WebClient() 
    let! html = client.DownloadStringAsync(url) 
    return html } 

(比如在索瑪最近post描述)我得到一個錯誤信息:

類型約束不匹配。該類型單位不與型異步<兼容「一>型‘單位’不與兼容型」異步<‘一>’

編輯:我真的問使用的一般問題* Async()方法,WebClient只是一個簡單的例子。微軟says「......你應該儘可能地使用基於事件的異步模式[而不是BeginFoo()/ EndFoo()]公開異步特性......」所以我認爲應該有一種簡單的方法來使用任意*來自F#的Async()方法。

回答

5

WebClient.DownloadStringAsync方法是.NET框架的一部分。它會引發一個事件來指示其進展,並且其返回類型爲unit,因此您不想使用它,並且將它包裝在async對象中沒有任何優勢。

的F#的PowerPack定義一個擴展方法,val webclient.AsyncDownloadString : uri -> Async{string}

let Download(url : Uri) = 
    async { 
    let client = new WebClient() 
    client.Encoding <- Encoding.GetEncoding("utf-8") 
    let! html = client.AsyncDownloadString(url) 
    return html } 

不幸的是,名稱衝突與現有的Web客戶端的方法,其可以理解造成混淆的選擇。不過,我相信所有的F#異步擴展都以Async*開頭。


[編輯成響應添加到評論:]

通常,.NET使用併發的BeginFoo/EndFoo圖案。如果類型正確,則可以使用Async.BuildPrimitive beginMethod endMethod,這將返回方法的異步封裝。

有時候對象不會使用這種模式,比如WebClient,並且實際上您必須使用Async.AwaitEvent來等待事件被觸發,或者編寫自己的循環來重複檢查是否設置了布爾值。這是一個不錯的article on converting events to Async objects

對於它的價值,如果你安裝了F#,你還應該有源代碼,它可以讓你瞭解F#團隊如何實現它們的異步擴展。在我的機器上,相關文件位於:

C:\Program Files\FSharp-1.9.6.16\source\fsppack\FSharp.PowerPack\AsyncOperations.fs 
+1

那麼這個問題 - 使用* Async()方法如何在一般情況下處理?我是否必須每次都寫一個自己的F#擴展方法? – 2009-10-12 16:46:06

+0

不再是:http://msdn.microsoft.com/en-us/library/ms228966.aspx「...你應該儘可能使用基於事件的異步模式暴露異步功能......」 – 2009-10-12 17:37:04