为什么推荐的处置模式会在每一层级增加一个处置字段?

问题描述 投票:0回答:1

Dispose 模式是出了名的复杂,尤其是当我们有一个需要在不同层次上处理事物的类的层次结构时。推荐的实现如下,取自 实现一个处置方法 - Microsoft Docs.

using System;

class BaseClass : IDisposable
{
    // To detect redundant calls
    private bool _disposed = false;

    ~BaseClass() => Dispose(false);

    // Public implementation of Dispose pattern callable by consumers.
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    // Protected implementation of Dispose pattern.
    protected virtual void Dispose(bool disposing)
    {
        if (_disposed)
        {
            return;
        }

        if (disposing)
        {
            // TODO: dispose managed state (managed objects).
        }

        // TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
        // TODO: set large fields to null.

        _disposed = true;
    }
}

using Microsoft.Win32.SafeHandles;
using System;
using System.Runtime.InteropServices;

class DerivedClass : BaseClass
{
    // To detect redundant calls
    private bool _disposed = false;

    // Instantiate a SafeHandle instance.
    private SafeHandle _safeHandle = new SafeFileHandle(IntPtr.Zero, true);

    // Protected implementation of Dispose pattern.
    protected override void Dispose(bool disposing)
    {
        if (_disposed)
        {
            return;
        }

        if (disposing)
        {
           // Dispose managed state (managed objects).
            _safeHandle?.Dispose();
        }

        _disposed = true;

        // Call base class implementation.
        base.Dispose(disposing);
    }
}

我不明白的是,在这样的实现中,我们增加一个 _disposed 层次结构中的每一级的字段?相反,我们可以处理好 _disposed 只在层次结构的最上层(直接实现了 IDisposable 而在派生类中不关心它。

类似这样。

using System;

class BaseClass : IDisposable
{
    // To detect redundant calls
    private bool _disposed = false;

    ~BaseClass()
    {
       if (_disposed)
       {
          return;
       }

       Dispose(false);
       _disposed = true;
    }

    // Public implementation of Dispose pattern callable by consumers.
    public void Dispose()
    {
        if (_disposed)
        {
            return;
        }

        Dispose(true);
        GC.SuppressFinalize(this);
        _disposed = true;
    }

    // Protected implementation of Dispose pattern.
    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            // TODO: dispose managed state (managed objects).
        }

        // TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
        // TODO: set large fields to null.
    }
}

using Microsoft.Win32.SafeHandles;
using System;
using System.Runtime.InteropServices;

class DerivedClass : BaseClass
{
    // Instantiate a SafeHandle instance.
    private SafeHandle _safeHandle = new SafeFileHandle(IntPtr.Zero, true);

    // Protected implementation of Dispose pattern.
    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
           // Dispose managed state (managed objects).
            _safeHandle?.Dispose();
        }

        // Call base class implementation.
        base.Dispose(disposing);
    }
}

这是一个被广泛使用的代码样本 所以肯定有一个很好的理由让它被重复实现。_disposed 在每一级都有,但我就是找不到。

在基类里多了一点代码,但在派生类里就不用担心了,还去掉了一些重复的信息。

我还漏了什么?

编辑一下。

正如@InBetween所说,我的实现有一个缺点,就是如果你需要检查你的对象是否在派生类的一个方法中被处理,你将无法检查它。让我们通过把它变成一个私有集的保护属性来纠正这个问题。

using System;

class BaseClass : IDisposable
{
    // To detect redundant calls
    protected bool Disposed { get; private set; } = false;

    ~BaseClass()
    {
       if (Disposed)
       {
          return;
       }

       Dispose(false);
       Disposed = true;
    }

    // Public implementation of Dispose pattern callable by consumers.
    public void Dispose()
    {
        if (Disposed)
        {
            return;
        }

        Dispose(true);
        GC.SuppressFinalize(this);
        Disposed = true;
    }

    // Protected implementation of Dispose pattern.
    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            // TODO: dispose managed state (managed objects).
        }

        // TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
        // TODO: set large fields to null.
    }
}

using Microsoft.Win32.SafeHandles;
using System;
using System.Runtime.InteropServices;

class DerivedClass : BaseClass
{
    // Instantiate a SafeHandle instance.
    private SafeHandle _safeHandle = new SafeFileHandle(IntPtr.Zero, true);

    public void DoSomething()
    {
       if(Disposed)
       {
           throw new ObjectDisposedException("Cannot access disposed resource");
       }
    }    

    // Protected implementation of Dispose pattern.
    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
           // Dispose managed state (managed objects).
            _safeHandle?.Dispose();
        }

        // Call base class implementation.
        base.Dispose(disposing);
    }
}
c# .net dispose idisposable
1个回答
4
投票

原因很简单。在你的实现中,你不能使用 _disposed 的派生类型中,以检查是否有任何方法在对象已经被处置时被调用,并采取必要的行动。在你的实现中,你需要创建你自己的多余的flag isDisposed 的目的;你已经有一个 "免费 "的模式本身按照指南。

虽然可以做一个关于制作 _disposed protected.


4
投票

如果你从一个可抛弃类继承,两个条件之一必须是真的。

  1. 你的子类没有引入一个新的一次性资源。在这种情况下,你不需要重写 Dispose 而这个问题是没有意义的。

  2. 你的子类引入了一个新的一次性资源。在这种情况下,你要重写 Dispose,插入自己的处理代码,然后调用 base.Dispose. 该 _disposed 标志是为了帮助你记住防止你的处置代码执行两次。

您当然可以删除 _disposed 如果你愿意。但你可能并不太在意基类的。_disposed 旗帜,如果它甚至有一个。它担心的是它要处置的东西,而你担心的是你的东西。

© www.soinside.com 2019 - 2024. All rights reserved.