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)
您将获得异常,因为您传递给的函数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你在处理实例之后创建的任何闭包,否则你最终会得到你现在看到的同样的例外.