2013-04-26 51 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

相关问题