将IDisposable(一次性模式)实现为服务(类成员) [英] Implementing IDisposable (the Disposable Pattern) as a service (class member)

查看:152
本文介绍了将IDisposable(一次性模式)实现为服务(类成员)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Disposable模式是在每个类的基础上重新实现的模式。因此,我一直在寻找一种概括的方法。我几年前遇到的问题是,即使您将其实现为类本身,也无法从Disposable实现和另一个类中都派生一个对象(C#不支持多继承)。

The Disposable pattern is one that is re-implemented on a per class basis. So, I was looking for a way to generalize it. The problem I ran into a few years ago is that, even if you implement it as class itself, you can't have an object derive from both your Disposable implementation and from another class (C# doesn't support multi-inheritance).

问题是,您如何以通用方式实现Disposable模式,因此您无需为每个实现IDisposable的类显式编写它

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

Here is the standard Disposable pattern that is generated for you by Visual Studio (VS 2015).

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
}


推荐答案

我的实现



因此,这是我想出的解决方案。

My implementation

So, here is the solution I came up with.

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<>成员。这是一个有关仅在托管资源时如何使用它的示例。

This class allows you to create a DisposableService<> member for your class that implements IDisposable. Here is an example on how to use it when you only have managed resources.

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将自动运行。

  • 始终确保创建

  • How it works

    • The DisposeService will run it's Dispose on your object's Dispose.
    • The DisposeService's dispose will run your Managed and Unmanaged Action that you provide on initialization (or update in derived classes).
    • The GC.SuppressFinalize will run automatically if an UnmanagedAction is provided.
    • Always make sure to create the DisposableService<> as the first action of your constructor.
    • 因此,这是将服务与非托管资源一起使用的示例。 p>

      So, here is an example of using this service with unmanaged resources.

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

      轻松榨柠檬。

      总的来说,应该更干净一些,然后管理Microsoft一直在使用的blarg的过程区域。自2005年以来提供...

      Overall, should be cleaner then managing that procedural region of blarg that Microsoft has been providing since 2005...

      编辑:我认为在构造函数中传递的 this可能是一个问题。但是,它似乎不是: 传递 this是否是错误的做法?作为论点? 请记住,请在操作中放入null检查,这样就不会尝试处理null的东西。 :-)

      I thought the 'this' being passed in the constructor might be a concern. But, it doesn't seem to be: Is it a bad practice to pass "this" as an argument? Just remember to put the null checks in your actions so you don't try to Dispose something that is null. :-)

      这篇关于将IDisposable(一次性模式)实现为服务(类成员)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆