在这种情况下,.Net 会为我调用 Dispose 吗?

Will .Net call Dispose for me in this case?

根据我在 Internet 上阅读的内容,您应该始终在 IDisposable 对象 不再需要它们时立即调用它们

这个问题是关于一个特殊情况,在这种情况下(对我来说)很明显 不再需要对象,也许 .Net 可能会为我调用 dispose。

例证:

type Foo() =
    let disposable:IDisposable = // create an IDisposable
    ...

问题是:一旦类型 Foofoo 变得不可访问(垃圾收集的候选对象;没有指向它的引用),disposable 会被处理掉吗?

我的猜测是,一旦没有对 foo 的引用,disposable 就不会被处置,因为没有实时发生引用计数(AFAIK),但是 可能foo 被垃圾收集时.Net 将处理 disposable.

目前,我避免在该位置创建一次性对象,因为我不完全清楚谁应该调用 dispose,即使 .Net 调用 dispose,我也不知道它会在多长时间内发生。

在这种情况下可能很明显,但除非您要求,否则不会调用 .Dispose(例如,将 let 替换为 use)。

当对象 GC:ed(它可能永远不会,非确定性等等)如果对象有终结器,那么 GC 会将对象添加到终结器队列。

终结器线程然后 可能 运行 对象上的终结器,其中终结器可以释放非托管资源但 不是 托管资源,例如实现 IDisposable 的其他 .NET 对象。此外,很难在终结器中释放具有线程亲和性的资源,例如 Windows 句柄,因为它是错误的线程。

最终对象可能得到GC:ed.

因此 GC 非常适合纯内存资源,对于其他资源,我们通过调用 Dispose 或使用 use.

使用确定性和显式资源收集

Eric Lippert 最近写了一篇有趣的文章 blog,介绍了终结器的精彩世界,值得一读以了解更多详细信息。

以下是您需要了解的有关 IDisposable 的所有信息:CLR Inside Out: 深入研究 IDisposable

简而言之,Dispose不会被垃圾回收器调用,但是如果对象有finalizer,finalizer就会被调用。 IDisposable 所有包含非托管资源的精心设计的实现都将具有与 Dispose 方法相同的终结器。

但是,如果您等待垃圾收集器清理您的内存,您将获得不确定的行为,而且您的应用程序也可能会以非最佳方式使用内存。 不处理一次性资源可能会对性能产生不利影响。

但是,在 F# 中,通常很容易确保自动释放对象:只需使用 use 关键字而不是 let 绑定。

但是,这在这个特定示例中不起作用,因为 Foo 是 class,这意味着 disposable 不是 ,而是一个字段。这意味着它不会超出范围,直到对象本身超出范围,但是据我所知,没有特定的语言结构来支持它(C# 中也不存在)。

以下是为 Foo 实现 Dispose 习语 的方法:

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

唯一不太符合 'standard' Dispose 习语的部分是虚拟 Dispose 方法 (bool -> unit) 不受保护,因为 F# 不支持那个 (AFAIK)。

如前所述,垃圾收集器不会直接调用 Dispose,尽管终结器会在 disposable 被垃圾收集时调用,并有望以类似的方式清理其资源.

不幸的是,将 let 更改为 use 并不能解决您在这种情况下的问题,因为它会给您带来编译器错误:

type Foo() =    
    use disposable:IDisposable = // create an IDisposable

// error FS0523: 'use' bindings are not permitted in primary constructors

您的选择是:

  1. Foo

    的方法中定义disposable
    type Foo() = 
        member this.DoSomething() =
            use disposable:IDisposable = // create an IDisposable
    
  2. 或者,使 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()