When working with objects that implement IDisposable
, the common pattern is;
using(ManagementObject mObj = new ManagementObject())
{
//Work with mObj
}
However, in the instance of System.Management.ManagementObject
, IDisposable
has been declared on the ultimate parent class, in this instance, System.ComponentModel.Component
Dispose
has been implemented as follows (extracted using ILSpy):
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
Dispose
on the ManagementObject
however, has been implemented as follows:
// System.Management.ManagementObject
/// <summary>Releases all resources used by the Component.</summary>
public new void Dispose()
{
if (this.wmiClass != null)
{
this.wmiClass.Dispose();
this.wmiClass = null;
}
base.Dispose();
GC.SuppressFinalize(this);
}
It appears that on completion of the using
block, Dispose
is called from the class which directly implements the interface; that is System.Component
, and so the wmiClass
field is not cleaned up at this point as this implementation is not executed.
If I recreate this with a simple hierarchy:
public class Parent, IDisposable {
public void Dispose(){
System.WriteLine("Parent Disposing");
}
}
public class Child : Parent {
public new void Dispose()
{
System.WriteLine("Child Disposing");
base.Dispose();
}
}
and write a small test program;
using (Child child = new Child())
{
System.WriteLine("Do Stuff");
}
I get the output: Do Stuff, Parent Disposing
Generally, if we wanted the inheritance to work as expected wouldn't it have been safer to declare Dispose
as virtual
on Parent
and override
on Child? If I do that I get exactly the order of events expected vs what happens in the original example (which makes sense if Dispose is being called on the class that directly implemented the interface).
Is there a reason why you'd implement Dispose in this way rather than as a virtual call on the base class? This forces the use of a try {} finally {}
pattern where you explicitly call the Dispose implementation to get the expected result.