Release 中出现 ObjectDisposedException 错误,但 Debug 中没有
ObjectDisposedException error in Release, but not in Debug
我正在编写 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# 应用程序后文件为空白。
从终结器引用托管对象不是一个好主意,因为 GC 可能已经收集了它们。终结器仅在分配非托管内存(如 IntPtr)时是必需的,并且您希望确保它始终被释放。实现在内部创建一次性对象的类型(如 FileStream)的正确方法是使用 dispose pattern。这使该类型的用户有机会及时释放资源。
总而言之,VMwareInterface 应该使用上面的模式实现 IDisposable。不需要终结器覆盖。
编辑:更正了您的缩进。
let cleanup (disposing:bool) =
if not disposed then
disposed <- true
if disposing then
vimClient.Logout()
streamWriter.Close()
fileStream.Close()
我正在编写 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# 应用程序后文件为空白。
从终结器引用托管对象不是一个好主意,因为 GC 可能已经收集了它们。终结器仅在分配非托管内存(如 IntPtr)时是必需的,并且您希望确保它始终被释放。实现在内部创建一次性对象的类型(如 FileStream)的正确方法是使用 dispose pattern。这使该类型的用户有机会及时释放资源。
总而言之,VMwareInterface 应该使用上面的模式实现 IDisposable。不需要终结器覆盖。
编辑:更正了您的缩进。
let cleanup (disposing:bool) =
if not disposed then
disposed <- true
if disposing then
vimClient.Logout()
streamWriter.Close()
fileStream.Close()