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.