qua*_*con 3 .net c# dispose idisposable finalizer
我已经仔细阅读了这篇文章,并且似乎清楚地指出了在所有IDisposable实施情况下都应该实施处置模式。我试图理解为什么在我的班级仅持有托管资源(即其他IDisposable成员或安全句柄)的情况下需要实现处置模式的原因。为什么我不能写
class Foo : IDisposable
{
IDisposable boo;
void Dispose()
{
boo?.Dispose();
}
}
Run Code Online (Sandbox Code Playgroud)
如果可以肯定地知道没有非托管资源,并且没有指向Dispose终结器调用方法的信息,因为托管资源没有从终结器中释放出来?
更新:为了增加一些清晰度。讨论似乎归结为以下问题:是否需要为每个实现的基础公共非密封类实现处置模式IDisposable。但是,当没有非托管资源的基类不使用dispose模式而具有非托管资源的子类确实使用此模式时,我找不到层次结构的潜在问题:
class Foo : IDisposable
{
IDisposable boo;
public virtual void Dispose()
{
boo?.Dispose();
}
}
// child class which holds umanaged resources and implements dispose pattern
class Bar : Foo
{
bool disposed;
IntPtr unmanagedResource = IntPtr.Zero;
~Bar()
{
Dispose(false);
}
public override void Dispose()
{
base.Dispose();
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposed)
return;
if (disposing)
{
// Free any other managed objects here.
//
}
// close handle
disposed = true;
}
}
// another child class which doesn't hold unmanaged resources and merely uses Dispose
class Far : Foo
{
private IDisposable anotherDisposable;
public override void Dispose()
{
base.Dispose();
anotherDisposable?.Dispose();
}
}
Run Code Online (Sandbox Code Playgroud)
更重要的是,对我来说,当实现仅对他们所知道的事情负责时,看起来更好地分离了关注点。
这个
private class Foo : IDisposable
{
IDisposable boo;
public void Dispose()
{
boo?.Dispose();
}
}
Run Code Online (Sandbox Code Playgroud)
很好。照原样
public sealed class Foo : IDisposable
{
IDisposable boo;
public void Dispose()
{
boo?.Dispose();
}
}
Run Code Online (Sandbox Code Playgroud)
如果我没有使用virtual Dispose方法实现上述未实现的密封基类,怎么办?
从文档:
因为未定义垃圾收集器在完成过程中销毁托管对象的顺序,所以使用值为false调用此Dispose重载可防止终结器尝试释放可能已经回收的托管资源。
访问已被回收的托管对象,或在其被处置后访问其属性(可能由另一个终结器访问),将导致在终结器中引发异常,这很糟糕:
如果Finalize或Finalize的覆盖引发异常,并且运行时不是由覆盖默认策略的应用程序托管,则运行时将终止进程,并且不会执行活动的try / finally块或终结器。如果终结器无法释放或破坏资源,则此行为可确保过程完整性。
因此,如果您有:
public class Foo : IDisposable
{
IDisposable boo;
public virtual void Dispose()
{
boo?.Dispose();
}
}
public class Bar : Foo
{
IntPtr unmanagedResource = IntPtr.Zero;
~Bar()
{
this.Dispose();
}
public override void Dispose()
{
CloseHandle(unmanagedResource);
base.Dispose();
}
void CloseHandle(IntPtr ptr)
{
//whatever
}
}
Run Code Online (Sandbox Code Playgroud)
〜Bar-> Bar.Dispose()-> base.Dispose()-> boo.Dispose()但是boo可能已被GC回收。