c# - 是否真的需要只为托管资源实现处置模式

标签 c# .net dispose idisposable finalizer

我仔细阅读了 this文章,它似乎明确指出在 IDisposable 实现的所有情况下都应该实现处置模式。我试图理解为什么我需要在我的类仅包含托管资源(即其他 IDisposable 成员或安全句柄)的情况下实现处置模式。为什么我不能写

class Foo : IDisposable
{
    IDisposable boo;

    void Dispose()
    {
        boo?.Dispose();
    }
}

如果明确知道没有非托管资源并且没有必要从终结器调用 Dispose 方法,因为托管资源没有从终结器中释放?

更新:为了增加一些清晰度。讨论似乎归结为是否需要为每个实现 IDisposable 的公共(public)非密封基类实现处置模式的问题。但是,当没有非托管资源的基类不使用处置模式而具有非托管资源的子类使用此模式时,我找不到层次结构的潜在问题:

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();
    }
}

更重要的是,对我来说,当实现只对他们知道的事情负责时,关注点分离看起来更好。

最佳答案

这个

private class Foo : IDisposable
{
    IDisposable boo;

    public void Dispose()
    {
        boo?.Dispose();
    }
}

完全没问题。原样

public sealed class Foo : IDisposable
{
    IDisposable boo;

    public void Dispose()
    {
        boo?.Dispose();
    }
}

What could go wrong if I have public not sealed base class implemented as above with virtual Dispose method ?

来自docs :

Because the order in which the garbage collector destroys managed objects during finalization is not defined, calling this Dispose overload with a value of false prevents the finalizer from trying to release managed resources that may have already been reclaimed.

访问一个已经被回收的托管对象,或者在它被释放(可能被另一个终结器)后访问它的属性将导致在终结器中引发异常,即 bad :

If Finalize or an override of Finalize throws an exception, and the runtime is not hosted by an application that overrides the default policy, the runtime terminates the process and no active try/finally blocks or finalizers are executed. This behavior ensures process integrity if the finalizer cannot free or destroy resources.

所以如果你有:

   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
        }
    }

~Bar -> Bar.Dispose() -> base.Dispose() -> boo.Dispose() 但是 boo 可能已经被 GC 回收了。

关于c# - 是否真的需要只为托管资源实现处置模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55712301/

相关文章:

c# - 在C#中以MAT格式保存数据

c# - 服务器端技能和桌面开发技能有什么区别?

c# - 在 if 语句中使用 'if (variable == true)' 与 'if (variable)' 有什么不同吗?

.net - 什么二进制重写器用于实现 Microsoft 的代码契约(Contract)?

c# - 在 C# 中 Dispose 调用 Dispose(IsDisposing) 模式的目的?

c# - C#中的一次性单例

c# - MVC4 Razor View header 中@model 和@inherit 的区别?

c# - 如何根据当前键盘布局将虚拟键码转换为字符?

c# - dotnet core 1.1.1、mvc 1.1.2 中未调用模型绑定(bind)程序提供程序

c# - 如果您已经关闭 SqlConnection,是否需要关闭/处置 SqlDataReader?