【问题标题】:Implementing IDisposable (the Disposable Pattern) as a service (class member)将 IDisposable(Disposable 模式)实现为服务(类成员)
【发布时间】:2015-09-04 21:05:18
【问题描述】:

Disposable 模式是基于每个类重新实现的模式。所以,我一直在寻找一种方法来概括它。几年前我遇到的问题是,即使你将它实现为类本身,你也不能从你的 Disposable 实现和另一个类中派生一个对象(C# 不支持多继承)。

问题是,如何制定通用的方法来实现 Disposable 模式,这样您就不需要为每个实现 IDisposable 的类显式编写它?

这是 Visual Studio (VS 2015) 为您生成的标准 Disposable 模式。

public class TestClass : IDisposable {
    #region IDisposable Support

    private bool disposedValue = false; // To detect redundant calls

    protected virtual void Dispose(bool disposing) {
        if (!disposedValue) {
            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.

            disposedValue = true;
        }
    }

    // TODO: override a finalizer only if Dispose(bool disposing) above has code to free unmanaged resources.
    // ~DisposeTest() {
    //   // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
    //   Dispose(false);
    // }

    // This code added to correctly implement the disposable pattern.
    public void Dispose() {
        // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
        Dispose(true);
        // TODO: uncomment the following line if the finalizer is overridden above.
        // GC.SuppressFinalize(this);
    }

    #endregion
}

【问题讨论】:

  • 感觉基于意见 - 如果您更喜欢包含而不是继承并且从不混合原生类和托管类(为原生资源创建单独的托管包装器,如 SafeHandle),则模式将简化为单一方法 public void Dispose().. . 所以我想说 - 如果你需要完整的IDisposable 模式,你可能正在构建深层的类层次结构。
  • @AlexeiLevenkov 微软多年前就创造了这种模式。如果您想要完整的解释,您可以在这里阅读:joeduffyblog.com/2005/04/08/… 我不倾向于使用许多非托管资源或具有非托管资源的类。但当我这样做时,我只是希望它尽可能简单明了。

标签: c# design-patterns idisposable disposable


【解决方案1】:

我的实现

所以,这是我想出的解决方案。

public class DisposeService<T> where T : IDisposable {
    private readonly T _disposee;
    public Action<T> ManagedAction { get; set; }
    public Action<T> UnmanagedAction { get; set; }

    public DisposeService(T disposee, Action<T> managedAction = null, Action<T> unmanagedAction = null) {
        _disposee = disposee;
        ManagedAction = managedAction;
        UnmanagedAction = unmanagedAction;
    }

    private bool _isDisposed;

    public void Dispose(bool isDisposing) {
        if (_isDisposed) return;
        if (isDisposing && ManagedAction != null) {
            ManagedAction(_disposee);
        }
        var hasUnmanagedAction = UnmanagedAction != null;
        if (hasUnmanagedAction) {
            UnmanagedAction(_disposee);
        }
        _isDisposed = true;
        if (isDisposing && hasUnmanagedAction) {
            GC.SuppressFinalize(_disposee);
        }
    }
}

此类允许您为实现 IDisposable 的类创建 DisposableService 成员。下面是一个示例,说明当您只有托管资源时如何使用它。

public class TestClass : IDisposable {
    protected readonly DisposeService<TestClass> DisposeService;
    private readonly SafeHandle _handle;

    public TestClass() {
        DisposeService = new DisposeService<TestClass>(this, ps => { if (_handle != null) _handle.Dispose(); });
        _handle = new SafeFileHandle(IntPtr.Zero, true);
    }

    public void Dispose() {
        DisposeService.Dispose(true);
    }
}

工作原理

  • DisposeService 将在对象的 Dispose 上运行它的 Dispose。
  • DisposeService 的 dispose 将运行您在初始化(或在派生类中更新)时提供的托管和非托管操作。
  • 如果提供了 UnmanagedAction,GC.SuppressFinalize 将自动运行。
  • 始终确保创建 DisposableService 作为构造函数的第一个操作。

所以,这里是一个使用非托管资源的服务的示例。

public class TestClass : IDisposable {
    protected readonly DisposeService<TestClass> DisposeService;
    private readonly SafeHandle _handle;

    public TestClass() {
        DisposeService = new DisposeService<TestClass>(this,
            ps => { if (_handle != null) _handle.Dispose(); },
            ps => { /* Free unmanaged resources here */ });
        _handle = new SafeFileHandle(IntPtr.Zero, true);
    }

    public void Dispose() {
        DisposeService.Dispose(true);
    }

    ~TestClass() {
        DisposeService.Dispose(false);
    }
}

还有一个从上面的类创建派生类的例子。

public class TestClassDerived : TestClass, IDisposable {
    private readonly SafeHandle _derivedHandle;

    public TestClassDerived() {
        // Copy the delegate for the base's managed dispose action.
        var baseAction = DisposeService.ManagedAction;
        // Update the managed action with new disposes, while still calling the base's disposes.
        DisposeService.ManagedAction = ps => {
            if (_derivedHandle != null) {
                _derivedHandle.Dispose();
            }
            baseAction(ps);
        };
        _derivedHandle = new SafeFileHandle(IntPtr.Zero, true);
    }
}

简单的 peasy 柠檬汁。您保留对基类委托的引用并将其作为派生类委托的一部分调用。

总的来说,应该比管理微软自 2005 年以来一直提供的 blarg 程序区域更干净......

编辑:我认为在构造函数中传递的“this”可能是一个问题。但是,它似乎不是:Is it a bad practice to pass "this" as an argument? 请记住将空检查放在您的操作中,这样您就不会尝试处置空的东西。 :-)

【讨论】:

  • 这看起来是一个非常有趣的解决方案,感谢您的分享。不过,您似乎并没有对 stackoverflow 有疑问:P。
  • @dustmouse 我做了,我搜索了,搜索了一个实现,但找不到一个。我意识到如何实现它,所以我没有要求等待响应,而是自己制作了它,但发布了我的实现,以便其他人可以使用它。 :-P
  • 很公平。无论如何我都赞成它,因为我认为这是一个很好的解决方案。
猜你喜欢
  • 2011-03-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-30
  • 1970-01-01
相关资源
最近更新 更多