对于我在互联网上阅读的内容,您应该在不再需要的情况下随时调用IDisposable
个对象处置。
这个问题是关于一个特殊情况,(对我而言)显然不再需要对象,也许.Net可能会为我调用处理。
案例:
type Foo() =
let disposable:IDisposable = // create an IDisposable
...
问题是:只要类型foo
的{{1}}无法访问(垃圾收集的候选者;没有指向它的引用),Foo
会被处置吗?
我的猜测是disposable
一旦没有disposable
的引用就不会被处置,因为实时没有引用计数(AFAIK),但可能当foo
被垃圾收集时.Net将处置foo
。
现在,我避免在那个地方制造一次性用品,因为我不清楚谁应该叫处理,即使.Net称为处置,我也不知道它会多久发生。
答案 0 :(得分:4)
在这种情况下可能很明显,但除非您要求,否则无法调用.Dispose
(例如,将let
替换为use
)。
当对象是GC:ed(它可能永远不会是非确定性和所有)时,如果对象有终结器,那么GC会将对象添加到终结器队列。
终结器线程然后可能在终结器上运行终结器,终结器可以释放非托管资源但不托管资源,就像实现{{1}的其他.NET对象一样}。另外,由于它是错误的线程,因此很难在终结器中释放具有线程关联性的资源,如Windows句柄。
最后,对象可以获得GC:ed。
因此GC对于纯内存资源来说很棒(对某种类型),对于其他资源,我们通过调用IDisposable
或使用Dispose
来使用确定性和显式资源集合。
Eric Lippert最近在精彩的终结者世界中写了一篇有趣的blog,值得查看更多细节。
答案 1 :(得分:3)
如前所述,垃圾收集器不会直接调用Dispose
,但是当disposable
被垃圾收集时将调用终结器,并希望以类似的方式清理其资源。 / p>
不幸的是,将let
更改为use
并不能解决此问题,因为它会导致编译错误:
type Foo() =
use disposable:IDisposable = // create an IDisposable
// error FS0523: 'use' bindings are not permitted in primary constructors
您的选择是:
在disposable
Foo
type Foo() =
member this.DoSomething() =
use disposable:IDisposable = // create an IDisposable
或者,使Foo
IDisposable并将责任推给消费者
type Foo() =
let disposable:IDisposable = // create an IDisposable
interface IDisposable with
member this.Dispose() = disposable.Dispose()
member this.DoSomething() = ()
let bar () =
use t = new Foo()
t.DoSomething()
答案 2 :(得分:2)
以下是您需要了解的关于IDisposable
的所有信息:CLR Inside Out:
Digging into IDisposable
简而言之,垃圾收集器不会调用Dispose
,但如果对象有终结器,则会调用终结器。所有设计良好的IDisposable
实现包含非托管资源的实现都将使用与Dispose
方法相同的终结器。
但是,如果等待垃圾收集器清理内存,则会出现非确定性行为,并且您的应用程序也可能以非最佳方式使用内存。 不处置一次性资源可能会对性能产生不利影响。
但是,在F#中,通常很容易确保自动处理对象:只需使用use
关键字而不是let
绑定。
但是,这在这个特定的例子中并不起作用,因为Foo是一个类,这意味着disposable
不是值 ,而是一个字段。这意味着它不会超出范围,直到对象本身超出范围,但AFAIK,没有特定的语言结构来支持它(C#中也没有)。
以下是如何为Foo实现 Dispose idiom :
open System
type Foo() =
let disposable:IDisposable = // create an IDisposable
abstract member Dispose : disposing : bool -> unit
default this.Dispose disposing =
if disposing then disposable.Dispose ()
interface IDisposable with
member this.Dispose () =
this.Dispose true
GC.SuppressFinalize this
唯一不符合标准的部分'处理惯用法是虚拟的 Dispose 方法(bool -> unit
)没有受到保护,因为F#不支持(AFAIK)。