2013-04-26 90 views
2

我不希望添加StreamWriter參數寫入到文件的程序,但是當我試圖用一次性的StreamWriter來工作的我越來越:爲什麼我不能在對象成員中使用一次性對象?

An unhandled exception of type 'System.ObjectDisposedException' occurred in mscorlib.dll 

Additional information: Cannot write to a closed TextWriter. 

代碼:

let fileLogger = { 
    new IFlog with 
     member i.FLog level format = 
      use file = LogFile() 
      Printf.kfprintf 
       (fun f -> 
        fprintfn file "[%s][%A] " 
          <| level.ToString() 
          <| DateTime.Now 
        ) file (format) 

所以當我兩次調用FLog方法時,我得到了這個。

我可以使用它:member i.FLog file level format和控制一次性對象的頂層,但後來我失去了所有的抽象。

有沒有一些方法來使用這樣的一次性物體?或者我如何更改體系結構以避免將一次性參數傳遞到此函數中?

日誌文件是:

let mutable LogFileName = "F.log" 
let LogFile() = 
    match File.Exists(LogFileName) with 
    | false -> File.CreateText(LogFileName) 
    | true -> File.AppendText(LogFileName) 
+0

如果你有一個日誌文件,你爲什麼要處置 - 只是讓應用程序退出時該對象被丟棄 – 2013-04-26 11:29:10

+0

該名稱是可變的,可以改變。 – Cynede 2013-04-26 11:36:23

回答

5

你得到的異常,因爲你傳遞給Printf.kfprintf功能被編譯爲捕捉到你的file變量的引用的閉包 - 即,你TextWriter實例。一旦Printf.kfprintf返回,file超出範圍;編譯器會發現它並未在其他地方使用,因此會插入一些代碼來調用TextWriter上的Dispose()方法。當您致電FLog方法返回的封閉時,file已被處置,因此引發異常。

用一些代碼來顯示會更容易一些。這是F#編譯器如何編譯FLog方法:

member i.FLog level format = 
    try 
     let file = LogFile() 
     Printf.kfprintf 
      (fun f -> 
       fprintfn file "[%s][%A] " 
         <| level.ToString() 
         <| DateTime.Now 
       ) file (format) 
    finally 
     if file <> null then file.Dispose() 

你可以通過具有FLog聲明類型實現IDisposable,並使之類的file價值的一部分,而不是方法中聲明它的解決這個問題。當聲明類型的Dispose()方法被調用時,它應該只調用file.Dispose()。儘管如此,在使用實例後仍然需要注意不要使用您使用FLog創建的任何閉包,否則最終會出現與您現在看到的相同的異常。

+0

謝謝,但即使添加文件類休息期望抽象:S – Cynede 2013-04-27 04:31:56

相關問題