F#:只为第一个事件做一次动作,没有可变性/锁定?

kno*_*cte 5 f# locking webclient immutability

我有这个代码下载文件,并在控制台告诉我文件有多大:

use webClient = new WebClient()

let lockObj = new Object()
let mutable firstProgressEvent = true
let onProgress (progressEventArgs: DownloadProgressChangedEventArgs) =
    lock lockObj (fun _->
        if (firstProgressEvent) then
            let totalSizeInMB = progressEventArgs.TotalBytesToReceive / 1000000L
            Console.WriteLine ("Starting download of {0}MB...", totalSizeInMB)
        firstProgressEvent <- false
    )

webClient.DownloadProgressChanged.Subscribe onProgress |> ignore
let task = webClient.DownloadFileTaskAsync (uri, Path.GetFileName(uri.LocalPath))
task.Wait()
Run Code Online (Sandbox Code Playgroud)

有没有办法做同样的事情,但既不使用锁定也不使用可变的变量?

Kev*_*vin 5

以下是使用Reactive Extensions的一种方法:

open System.Net
open FSharp.Control

let webClient = new WebClient()
let disposable = 
  Observable.take 1 webClient.DownloadProgressChanged 
  |> Observable.subscribe (fun progress -> printfn "%A" (progress.TotalBytesToReceive))
Run Code Online (Sandbox Code Playgroud)

  • `FSharp.Control`命名空间中的[Observable](https://msdn.microsoft.com/visualfsharpdocs/conceptual/control.observable-module-%5bfsharp%5d)内置于F#中,没有`take`功能.所以要清楚,你需要这个NuGet包才能工作:[FSharp.Control.Reactive](https://www.nuget.org/packages/FSharp.Control.Reactive). (2认同)