I've used the wellknown Dispose Pattern in .NET several times as described in the official docs.
Now I have the following, rather simplified code:
public class FirstForeignDependency : IDisposable
{
// all the things from another library that I want to use in my code
}
public class SecondForeignDependency : IDisposable
{
// all the things from another library that I want to use in my code
}
public class MyParent
{
private readonly FirstForeignDependency _firstForeignDependency;
public MyParent()
{
_firstForeignDependency = new FirstForeignDependency();
}
}
public class MyChild : MyParent
{
private readonly SecondForeignDependency _secondForeignDependency;
public MyChild() : base()
{
_secondForeignDependency = new SecondForeignDependency();
}
}
As you can see, there are two dependencies FirstForeignDependency and SecondForeignDependency, representing any third-party dependency.
And there are the two types MyParent and MyChild within my codebase consuming the third-party dependencies.
Since I'm instantiating the dependencies, I'm also responsible for disposing them. Applying Microsoft's Dispose pattern would give me something like this:
public class FirstForeignDependency : IDisposable
{
// all the things from another library that I want to use in my code
}
public class SecondForeignDependency : IDisposable
{
// all the things from another library that I want to use in my code
}
public class MyParent : IDisposable
{
private readonly FirstForeignDependency _firstForeignDependency;
private bool _disposed;
public MyParent()
{
_firstForeignDependency = new FirstForeignDependency();
}
~MyParent()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (_disposed)
{
return;
}
if (disposing)
{
_firstForeignDependency?.Dispose();
}
_disposed = true;
}
}
public class MyChild : MyParent
{
private readonly SecondForeignDependency _secondForeignDependency;
private bool _disposed;
public MyChild() : base()
{
_secondForeignDependency = new SecondForeignDependency();
}
~MyChild()
{
this.Dispose(false);
}
protected override void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
_secondForeignDependency?.Dispose();
}
_disposed = true;
}
base.Dispose(disposing);
}
}
For me this code has some imperfections: the Dispose(bool) overload is intended to free unmanaged resources. Since I do only have managed resources, I think that I can safely skip this overload and the finalizers. So I ended up with this code:
public class FirstForeignDependency : IDisposable
{
// all the things from another library that I want to use in my code
}
public class SecondForeignDependency : IDisposable
{
// all the things from another library that I want to use in my code
}
public class MyParent : IDisposable
{
private readonly FirstForeignDependency _firstForeignDependency;
private bool _disposed;
public MyParent()
{
_firstForeignDependency = new FirstForeignDependency();
}
public virtual void Dispose()
{
if (_disposed)
{
return;
}
_firstForeignDependency?.Dispose();
_disposed = true;
}
}
public class MyChild : MyParent
{
private readonly SecondForeignDependency _secondForeignDependency;
private bool _disposed;
public MyChild() : base()
{
_secondForeignDependency = new SecondForeignDependency();
}
public override void Dispose()
{
if (!_disposed)
{
_secondForeignDependency?.Dispose();
_disposed = true;
}
base.Dispose(disposing);
}
}
Despite the fact that It does not adhere 100% to the original Dispose pattern, is there anything wrong with that simplification? Am I missing something with that approach?
Thanks!