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?
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 callsDispose
on each of its Level 0 and Level 1 members and on its base class.
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