我正在编写一个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后该文件为空。
答案 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()