Release中的ObjectDisposedException错误,但不在Debug中

时间:2015-07-06 17:36:51

标签: .net file-io f# runtime-error

我正在编写一个F#应用程序,并希望在执行期间记录某些信息。为此,我将控制台输出设置为.txt文件。我按如下方式这样做:

type VMwareInterface(serviceUrl:string, userName:string, password:string, baseSnapshotName:string) =  
    let vimClient = new VimClientImpl()
    let vimSession = vimClient.Login(serviceUrl, userName, password)

    // Logging
    let fileStream = new System.IO.FileStream(@"./VMInteractorLog.txt", System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.Write)
    let streamWriter = new System.IO.StreamWriter(fileStream)
    do System.Console.SetOut(streamWriter)

    [...]

    override x.Finalize () = 
        vimClient.Logout()
        streamWriter.Close()

    [...]

我按照以下方式记录:

System.Console.WriteLine("ERROR isolating the single VM matching name " + vmName)

当我在调试中运行应用程序时,一切都很顺利。该文件已创建,写入并正确关闭。不幸的是,当我在发布时运行它时,我收到以下错误:

System.ObjectDisposedException: Cannot access a closed file.
    at System.IO.__Error.FileNotOpen()
    at System.IO.FileStream.Flush(Boolean flushToDisk)
    at System.IO.FileStream.Flush()
    at System.IO.StreamWriter.Flush(Boolean flushStream, Boolean flushEncoder)
    at System.IO.StreamWriter.Dispose(Boolean disposing)
    at System.IO.StreamWriter.Close()

是什么导致这种情况?

编辑:

只是想补充说文件是在发布时正确创建的,但在收到上述错误之前没有写入。

EDIT2:

我已经实现了IDisposable接口,如下所示:

let mutable disposed = false

let cleanup (disposing:bool) = 
    if not disposed then
        disposed <- true

    if disposing then
        vimClient.Logout()
        streamWriter.Close()
        fileStream.Close()

interface System.IDisposable with
    member x.Dispose() =
        cleanup(true)
        System.GC.SuppressFinalize(x)

override x.Finalize () = 
    cleanup(false)

这已经删除了我得到的错误,但文件仍未写入(运行我的F#app后该文件为空。

1 个答案:

答案 0 :(得分:2)

从GC终结器中引用托管对象不是一个好主意,因为GC可能已经收集了它们。仅在分配像IntPtr这样的非托管内存时才需要终结器,并且您希望确保它始终被释放。实现在内部创建一次性用法的类型(如FileStream)的正确方法是使用dispose pattern。这为该类型的用户提供了及时释放资源的机会。

总之,VMwareInterface应该使用上面的模式实现IDisposable。不需要Finalizer覆盖。

编辑:更正了缩进。

let cleanup (disposing:bool) = 
    if not disposed then
        disposed <- true
        if disposing then
            vimClient.Logout()
            streamWriter.Close()
            fileStream.Close()