Reputation: 61
Here is a typical IDispose implementation. What I don't understand is the destructor? If the user of your class forgets to call Dispose, wouldn't you have a resource leak since the destructor will not call r1.Dispose()?
public class DisposableObject : IDisposable
{
private bool disposed;
private UnmanagedResource r1;
public DisposableObject()
{
r1 = new UnmanagedResource();
}
~DisposableObject()
{
this.Dispose(false);
}
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
// clean up managed resources
//call dispose on your member objects
r1.Dispose();
}
// clean up unmanaged resources
this.disposed = true;
}
}
public void SomeMethod()
{
if (this.disposed)
{
throw new ObjectDisposedException(this.GetType().FullName);
}
}
}
Upvotes: 0
Views: 2248
Reputation: 31394
The pattern exists because the garbage collector does not guarantee the order that managed objects will be garbage collected. So in the finalizer you are not guaranteed that the r1
reference is still valid.
Your r1
reference has a class name of UnmanagedResource
but it is clearly a managaged type. For a real unmanned resource you would only have an IntPtr
or some other token. To ensure that r1
does non like it's resource it should implement the same Dispose pattern and free it's unmanaged resource outside of the if (disposing)
check.
Upvotes: 0
Reputation: 4157
In .Net, we have a feature called Garbage Collection. Garbage Collection finalizes all Objects that are not referenced (any more). Your Destructor / finalizer then calls Dispose().
If your user forgets to remove those references, you will end up with sort-of a leak.
But that's what using
is for : avoid memory blockage by defining your disposables only in the scope of requirement.
Upvotes: 0
Reputation: 7523
If you really want to, you can add a finalizer:
~DisposeImplementation()
{
Dispose(false);
}
But it should only be used as a true last resort, not something to rely on directly.
Upvotes: 0
Reputation: 11040
The reason for the destructor (finalizer) to call Dispose is because Garbage Collector calls it before it collects an object, guaranteeing that at least at some point the UnmanagedResource will be freed.
By using using
and try...finally
you can enforce the resource to be disposed as soon as they are not needed
http://msdn.microsoft.com/en-us/library/system.object.finalize.aspx
Upvotes: 0
Reputation: 245389
If r1
is truly a native resource (which it doesn't look like it in your example), it should not be disposed of inside the if(disposing) block but after it. Pay particular attention to:
if (disposing)
{
// free managed resources
if (managedResource != null)
{
managedResource.Dispose();
managedResource = null;
}
}
// free native resources if there are any.
if (nativeResource != IntPtr.Zero)
{
Marshal.FreeHGlobal(nativeResource);
nativeResource = IntPtr.Zero;
}
From Implement IDisposable Correctly - MSDN
If r1
is a managed resource with its own implementation of IDisposable
, assuming it is implemented properly, any native resources will be cleaned up properly in its finalizer (which is why you don't need to worry about it in your own).
Upvotes: 2
Reputation: 498904
No - the GC will call the destructor once all references to the object are gone (this is not deterministic, however).
Upvotes: 2