实现IDisposable(一次性模式)作为服务(类成员)

时间:2015-09-04 21:05:19

标签: c# design-patterns idisposable disposable

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

问题是,如何实现一般方法来实现Disposable模式,这样您就不需要为实现IDisposable的类显式编写它?

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

{{1}}

1 个答案:

答案 0 :(得分:2)

我的实施

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

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

此类允许您创建DisposableService&lt;&gt;实现IDisposable的类的成员。以下是仅有托管资源时如何使用它的示例。

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。
  • DisposeService的dispose将运行您在初始化时提供的托管和非托管操作(或在派生类中更新)。
  • 如果提供了UnmanagedAction,GC.SuppressFinalize将自动运行。
  • 始终确保创建DisposableService&lt;&gt;作为构造函数的第一个动作。

因此,这是一个将此服务与非托管资源一起使用的示例。

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

易腻的柠檬挤压。您保留对基础委托的引用,并将其作为派生类委托的一部分进行调用。

总的来说,应该更清洁,然后管理自2005年以来微软一直提供的blarg程序区......

编辑:我认为&#39;这个&#39;在构造函数中传递可能是一个问题。但是,它似乎并非如此: Is it a bad practice to pass "this" as an argument? 只需记住将空检查放在您的操作中,这样您就不会尝试处理无效的内容。 : - )