DRY IDisposable Pattern

余生颓废 提交于 2019-12-10 10:06:34

问题


A lot of my classes repeat the below code to implement IDisposable. This seems to violate the DRY (Don't Repeat Yourself) principle. I could avoid some of the work by creating an AbstractDisposable base class, but that seems inappropriate / wouldn't work if I needed to extend other existing objects (assuming those objects weren't themselves disposable).

Another option would be to use a template/meta language where I could specify lists of managed and unmanaged resources for each class and have the generic Dispose Pattern auto generated when I build my project - but so far I've not played with meta languages / this seems extreme for such a common scenario.

public class SomeDisposableClass : IDisposable
{
    IDisposable _something; //a managed resource (unique to this class / here for illustration)

    /* ... loads of code unique to this class ... */

    #region Dispose Pattern
    private bool _disposed = false;

    ~SomeDisposableClass()
    {
        Dispose(false);
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        // Check to see if Dispose has already been called. 
        if (!this._disposed)
        {
            if (disposing)
            {
                // Dispose managed resources.
                if (this._something!=null) this._something.Dispose(); //(unique to this class / here for illustration)
            }
            // Clean up any unmanaged resources
            this._disposed = true;
        }
    }
    #endregion
}

Is there a good way to implement a suitable Dispose pattern without violating the DRY principle?


回答1:


I try to avoid IDisposable as best as I can. The problem is that it spreads throughout your code base. If a class has a disposable member, that class needs to implement IDisposable, too, etc.

Furthermore, IDisposable has problems when we are talking about type hierarchies.
A common scenario is to stick IDisposable onto a base class or even an interface if you think the derived classes need to free resources. However, most of the times, that's only an assumption and it really depends on the actual implementation if resource cleanup is needed or not, making the interface a leaky abstraction.
It would be better to only implement the interface if the class really needs it.
But this comes with its own problems:
How is the consumer of a certain interface supposed to know that the concrete instance he got - for example as a constructor parameter - needs to be disposed? He would have to explicitly check for it. And he would basically have to do this for every single instance of every non-sealed type he gets handed.

These are just two examples that show that you are best off to design your classes in a way so that they don't require the implementation of IDisposable.

However, if you really need to implement this interface, you should follow the Disposable Design Pattern as described by this CodeProject article.

It basically divides your types into two levels:

  • Level 0: Classes of level 0 contain only unmanaged resources, no managed ones. These classes need most of the usual default IDisposable pattern, although you don't have to implement the part that handles managed resources.
  • Level 1: Classes of level 1 contain only managed resources, both of Level 0 and 1. These classes only need a simplified implementation of IDisposable because they don't contain unmanaged resources. The implementation basically just calls Dispose on each of its Level 0 and Level 1 members and on its base class.



回答2:


i don't think you are violating the DRY principle here. Because although you are disposing in each class but you are essentially not doing the same thing.,



来源:https://stackoverflow.com/questions/18361535/dry-idisposable-pattern

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!