PROBLEM DESCRIPTION:
QUESTION
What is the best thing to do here? Should we
Please elaborate your answer. Thank you
public class FooClass : IDisposable
{
private readonly OtherDisposableClass _disposable;
private readonly string _imageSource;
private readonly string _action;
private readonly string _destination;
private bool _isInitialized;
public FooClass(OtherDisposableClass disposable)
{
_disposable = disposable;
}
~FooClass()
{
// Finalizer calls Dispose(false)
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
// Not possible because _disposable is marked readonly
_disposable = null;
}
}
The thing that does the creation of OtherDisposableClass
should be disposing of it... leave it alone in FooClass
(you can have it readonly
if you like).
Setting it to null will have no effect anyway, it will only set the reference from within FooClass to null (which is about to be disposed anyway).
EDIT
From the code given it looks like you don't even need to implement IDisposable here - this is just over complicating things. If you created an instance of OtherDisposableClass
within the constructor of FooClass
then you could implement IDisposable and simply call OtherDisposableClass.Dispose()
within the FooClass.Dispose()
.
Here FooClass is created with a dependency on OtherFooClass - OtherFooClass will outlive FooClass - therefore FooClass should be GC'd first and then there will be no reference to OtherDisposableClass remaining - which will allow it to be GC'd
The IDisposable
interface allows you to release unmanaged resources in a deterministic way. Unmanaged resources can be file handles, database connections etc. Disposing an object does not release any memory. Memory is only reclaimed by the garbage collector and you have very little control of when and how that is done. Disposing an object does not free any memory.
Still there is a connection between garbage collection and IDisposable
. If your class directly controls an unmanaged resource it should release this resource during finalization. However, having a finalizer on a class has a performance impact and should be avoided if possible. FooClass
does not directly control an unmanaged resource and the finalizer is not needed. However, to enforce the deterministic release of unmanaged resources it is important the FooClass.Dispose
calls OtherDisposableClass.Dispose
when Dispose
is called explictly (when disposing
is true
). If Dispose
is called from the finalizer you should not call methods on other managed objects because these objects may already have been finalized.
So to sum it up:
Garbage collection and reclaiming of memory is distinct from releasing unmanaged resources.
The Dispose
method should always release unmanaged resource.
The Dispose
method should call Dispose
on aggregated objects but only when called directly (not when called from the finalizer).
It should be possible to call Dispose
multiple times without any problems.
There is no point in setting an IDisposable
field to null
in the Dispose
method.
Avoid implementing finalizers if you do not control any unmanaged resources directly.
When implementing IDisposable
you have to take inheritance into consideration because both the base class and the derived class may want to call Dispose
on fields and/or release unmanaged resources. Sealing a class can avoid a lot of this complexity.
To elaborate on the point about setting the field to null
:
I assume that your code is sane. E.g., only FooClass
has a permanent reference to OtherDisposableClass
and both objects will after disposal be unusable (e.g. throw ObjectDisposedException
in all public methods except Dispose
).
If you set the reference to OtherDisposableClass
to null
then that instance becomes eligible for garbage collection because there are no references to the instance. However, after disposing FooClass
you surely will not keep an reference to that instance because it is unusable. This means that both the FooClass
and the OtherDisposableClass
are no longer reachable from a GC root and the entire object graph is now eligible for garbage collection. So there is no need to sever the link between FooClass
and OtherDisposableClass
because they will become eligible for garbage collection at the same time.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With