0

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.

dash
  • 89,546
  • 4
  • 51
  • 71
  • it should call child class method – Ehsan Sajjad Feb 19 '16 at 13:23
  • don't declare the method `new` – Daniel A. White Feb 19 '16 at 13:24
  • @DanielA.White does it matters ? – Ehsan Sajjad Feb 19 '16 at 13:25
  • @EhsanSajjad yes! `IDisposable foo = new Child()` will call `Parent`'s `Dispose`. – Daniel A. White Feb 19 '16 at 13:26
  • the System.Management is doing it wrong! – Daniel A. White Feb 19 '16 at 13:26
  • 1
    @EhsanSajjad It matters because it doesn't calls base class method and base method won't call it either. You should really override to properly dispose all objects. – Sriram Sakthivel Feb 19 '16 at 13:27
  • 5
    This is just a bug, the Microsoft programmer should have overridden the Dispose(bool) method. Par for the course btw, System.Management has several traps like these and code that uses it normally only works correctly when the garbage collector runs often enough. – Hans Passant Feb 19 '16 at 13:29
  • @HansPassant thank you, that is what I suspected – dash Feb 19 '16 at 15:02
  • @DanielA.White The answer is indeed in the linked question (although orthogonally). Much appreciated. (I'll clean up these thank you comments later) – dash Feb 19 '16 at 15:05
  • I should have annotated it a bit perhaps, it might have been intentional. System.Management is a wrapper for COM code. It Dispose() methods call Marshal.Release(). That's a pretty dangerous function and apt to generate an "COM object that has been separated from its underlying RCW cannot be used" exception. One that's pretty unjoyful to debug and not one their 1-800 support group would like to help solve. Something like that. – Hans Passant Feb 19 '16 at 15:06

0 Answers0