El uso de la cláusula no se puede llamar a Dispose?

Estoy usando Visual Studio 2010 para apuntar al perfil de cliente de .NET 4.0. Tengo una clase de C # para detectar cuándo se inicia / termina un proceso dado. Para esto, la clase utiliza un ManagementEventWatcher, que se inicializa como se muestra a continuación;query, scope ywatcher son campos de clase:

query = new WqlEventQuery();
query.EventClassName = "__InstanceOperationEvent";
query.WithinInterval = new TimeSpan(0, 0, 1);
query.Condition = "TargetInstance ISA 'Win32_Process' AND TargetInstance.Name = 'notepad.exe'";

scope = new ManagementScope(@"\\.\root\CIMV2");

watcher = new ManagementEventWatcher(scope, query);
watcher.EventArrived += WatcherEventArrived;
watcher.Start();

El controlador para el evento EventArrived se ve así:

private void WatcherEventArrived(object sender, EventArrivedEventArgs e)
{
    string eventName;

    var mbo = e.NewEvent;
    eventName = mbo.ClassPath.ClassName;
    mbo.Dispose();

    if (eventName.CompareTo("__InstanceCreationEvent") == 0)
    {
        Console.WriteLine("Started");
    }
    else if (eventName.CompareTo("__InstanceDeletionEvent") == 0)
    {
        Console.WriteLine("Terminated");
    }
}

Este código se basa enun artículo de CodeProject. Agregué la llamada ambo.Dispose() porque perdía memoria: aproximadamente 32 KB cada vez que se genera EventArrived, una vez por segundo. La fuga es obvia tanto en WinXP como en Win7 (64 bits).

Hasta ahora tan bueno. Tratando de ser concienzuda agregué untry-finally cláusula, así:

var mbo = e.NewEvent;
try
{
    eventName = mbo.ClassPath.ClassName;
}
finally
{
    mbo.Dispose();
}

No hay problema allí. Mejor aún, el C #using La cláusula es más compacta pero equivalente:

using (var mbo = e.NewEvent)
{
    eventName = mbo.ClassPath.ClassName;
}

Genial, solo que ahora la pérdida de memoria está de vuelta. ¿Que pasó?

Bueno, no lo sé. Pero intenté desmontar las dos versiones con ILDASM, que son casi pero no exactamente iguales.

IL detry-finally:

.try
{
  IL_0030:  nop
  IL_0031:  ldloc.s    mbo
  IL_0033:  callvirt   instance class [System.Management]System.Management.ManagementPath [System.Management]System.Management.ManagementBaseObject::get_ClassPath()
  IL_0038:  callvirt   instance string [System.Management]System.Management.ManagementPath::get_ClassName()
  IL_003d:  stloc.3
  IL_003e:  nop
  IL_003f:  leave.s    IL_004f
}  // end .try
finally
{
  IL_0041:  nop
  IL_0042:  ldloc.s    mbo
  IL_0044:  callvirt   instance void [System.Management]System.Management.ManagementBaseObject::Dispose()
  IL_0049:  nop
  IL_004a:  ldnull
  IL_004b:  stloc.s    mbo
  IL_004d:  nop
  IL_004e:  endfinally
}  // end handler
IL_004f:  nop

IL deusing:

.try
{
  IL_002d:  ldloc.2
  IL_002e:  callvirt   instance class [System.Management]System.Management.ManagementPath [System.Management]System.Management.ManagementBaseObject::get_ClassPath()
  IL_0033:  callvirt   instance string [System.Management]System.Management.ManagementPath::get_ClassName()
  IL_0038:  stloc.1
  IL_0039:  leave.s    IL_0045
}  // end .try
finally
{
  IL_003b:  ldloc.2
  IL_003c:  brfalse.s  IL_0044
  IL_003e:  ldloc.2
  IL_003f:  callvirt   instance void [mscorlib]System.IDisposable::Dispose()
  IL_0044:  endfinally
}  // end handler
IL_0045:  ldloc.1

Al parecer el problema es esta línea:

IL_003c:  brfalse.s  IL_0044

que es equivalente aif (mbo != null), asi quembo.Dispose() nunca se llama Pero, ¿cómo es posible que mbo sea nulo si pudiera acceder?.ClassPath.ClassName?

Tiene alguna idea sobre esto?

Además, me pregunto si este comportamiento ayuda a explicar la discusión no resuelta aquí:Pérdida de memoria en WMI al consultar registros de eventos.