2

我不想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并在顶层控制一次性对象,但后来我失去了所有的抽象。

有没有办法使用这样的一次性物品?或者我怎样才能改变架构以避免将一次性参数传递给这个函数?

日志文件是:

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

1 回答 1

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

您可以通过声明类型来解决此问题FLogimplement IDisposable,并使file值成为类的一部分,而不是在方法中声明它。当声明类型的Dispose()方法被调用时,它应该只调用file.Dispose(). 不过,您仍然需要注意不要使用FLog您在处置实例后创建的任何闭包,否则您最终会遇到与现在看到的相同的异常。

于 2013-04-26T12:52:51.767 回答