在这种情况下,.Net 会为我调用 Dispose 吗?
Will .Net call Dispose for me in this case?
根据我在 Internet 上阅读的内容,您应该始终在 IDisposable
对象 不再需要它们时立即调用它们 。
这个问题是关于一个特殊情况,在这种情况下(对我来说)很明显 不再需要对象,也许 .Net 可能会为我调用 dispose。
例证:
type Foo() =
let disposable:IDisposable = // create an IDisposable
...
问题是:一旦类型 Foo
的 foo
变得不可访问(垃圾收集的候选对象;没有指向它的引用),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
您的选择是:
在Foo
的方法中定义disposable
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()
根据我在 Internet 上阅读的内容,您应该始终在 IDisposable
对象 不再需要它们时立即调用它们 。
这个问题是关于一个特殊情况,在这种情况下(对我来说)很明显 不再需要对象,也许 .Net 可能会为我调用 dispose。
例证:
type Foo() =
let disposable:IDisposable = // create an IDisposable
...
问题是:一旦类型 Foo
的 foo
变得不可访问(垃圾收集的候选对象;没有指向它的引用),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
您的选择是:
在
的方法中定义Foo
disposable
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()