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

cnd*_*cnd 2 .net f# idisposable

我不想在StreamWriterWrite-To-File程序中添加参数,但是当我尝试使用一次性StreamWriter时,我得到了:

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

Additional information: Cannot write to a closed TextWriter.
Run Code Online (Sandbox Code Playgroud)

码:

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)
Run Code Online (Sandbox Code Playgroud)

所以当我两次调用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)
Run Code Online (Sandbox Code Playgroud)

Jac*_* P. 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 ()
Run Code Online (Sandbox Code Playgroud)

您可以通过使用声明类型的FLog实现来修复此问题IDisposable,并使file值成为类的一部分,而不是在方法中声明它.当Dispose()调用声明类型的方法时,它应该只调用file.Dispose().你仍然需要注意不要使用FLog你在处理实例之后创建的任何闭包,否则你最终会得到你现在看到的同样的例外.