I wanted a way to break the IDisposable chain where some nested class that you suddenly depend on now implements IDisposable and you don't want that interface to ripple up the layers of your composite. Basically, I have weak subscriptions to IObservable<T>'s via 'SubscribeWeakly()' that I want to clean up when I go away to not leak the wrapper instances just in case the Observable never fires. That was the motivation, but I use it for other stuff as well.
Another post had a similar problem, and the answer basically stated that you can still access the disposables in your finalizer. However, you're not guaranteed what order the finalizers are run in, so disposing might be problematic.
Therefore, I needed a way to guarantee that the disposable is kept alive so I can call Dispose() in my finalizer. So I looked at GCHandle, which allows C++ to hold (and keep alive) managed objects by pulling them and their aggregates into an application handle to keep them alive until the handle is free'd and the composite lifetime returns to the control of .NET's memory manager. Coming from C++, I thought behavior similar to std::unique_ptr would be good so I came up with something similar to AutoDisposer.
public class AutoDisposer
{
GCHandle _handle;
public AutoDisposer(IDisposable disposable)
{
if (disposable == null) throw new ArgumentNullException();
_handle = GCHandle.Alloc(disposable);
}
~AutoDisposer()
{
try
{
var disposable = _handle.Target as IDisposable;
if (disposable == null) return;
try
{
disposable.Dispose();
}
finally
{
_handle.Free();
}
}
catch (Exception) { }
}
}
In the class that needs to dispose resources when it goes away, I would just assign a field like _autoDisposables = new AutoDisposer(disposables). This AutoDisposer would then get cleaned up by the garbage collector around them same time the containing class does. However, I'm wondering what the issues would be with this technique. Right now I can think of the following:
Therefore, I use it sparingly when implementing IDisposable isn't too much of a burden, if I need to deterministically call Dispose(), or etc.
Does anybody see any other issues? Is this technique even valid?
I think you might've misunderstood IDispoable - the typical pattern on an IDisposable object is loosely:
void Dispose() { Dispose(true); }
void Dispose(bool disposing)
{
if (disposing)
{
// Free managed resources
}
// always free unmanaged resources
}
~Finalizer() { Dispose (false); }
Because the finalizer should always handle unmanaged resources, if you wait for it to run (which will be at some point in the future when memory constraints trigger the garbage collection, or it's triggered manually), you shouldn't leak. If you want to be deterministic about when those resources are freed, then you will have to expose IDispoable down your class hierarchy.
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