2009-10-12 68 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