为什么我不能在对象成员中使用一次性对象?

时间:2013-04-26 10:34:20

标签: .net f# idisposable

我不想将StreamWriter参数添加到Write-To-File过程中,但是当我尝试使用一次性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并在顶层控制一次性对象,但后来我失去了所有的抽象。

有没有办法像这样使用一次性物品?或者我如何更改架构以避免将一次性参数传递给此函数?

LogFile是:

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

1 个答案:

答案 0 :(得分:5)

您收到异常,因为传递给Printf.kfprintf的函数被编译为一个闭包,它捕获对file变量的引用 - 即您的TextWriter实例。 Printf.kfprintf返回后,file超出范围;编译器发现它没有在其他任何地方使用,因此插入一些代码来调用Dispose()上的TextWriter方法。当您调用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创建的任何闭包,否则您最终会遇到与现在相同的异常。