2017-01-03 34 views
5

我有这样的代码,下载文件,并告诉我在控制台有多大文件:F#:只对第一个事件做一次动作,没有可变性/锁定?

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() 

有没有办法做同样的,但既没有使用,也没有锁定可变瓦尔?

+1

我想你可能想在这里使用懒惰型 –

+0

究竟怎么了约翰? – knocte

+0

我不认为这可以用惰性来完成,因为每次处理事件时都要调用'.Force()',但是需要将第一个值烧入它,它不起作用。你可以看看使用[memoize模式](https://blogs.msdn.microsoft.com/dsyme/2007/05/31/a-sample-of-the-memoization-pattern-in-f/),它会打印一个,每次值改变(从不)。但是,如果不是更糟的话,这将与您已有的冗长一样。 – Stuart

回答

5

下面是使用无扩展的一种方法:

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)) 
+2

“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)。 – TheQuickBrownFox

+0

感谢@TheQuickBrownFox,我会问这个问题 – knocte