2010-06-09 12 views
24

Estoy iterando sobre una ManageObjectCollection. (Que es parte de la interfaz WMI).Combinación de foreach y uso de

Sin embargo, lo importante es la siguiente línea de código. :

foreach (ManagementObject result in results) 
{ 
    //code here 
} 

El punto es que ManageObject también implementa IDisposable, así que me gustaría poner la variable "número" en un bloque usando. ¿Alguna idea sobre cómo hacer esto, sin ser demasiado extraño o complejo?

Respuesta

24
foreach (ManagementObject result in results) 
using(result) 
{ 
    //code here 
} 

No es normalmente una buena práctica para asignar la variable fuera del bloque using porque el recurso estaría dispuesto, pero podría permanecer en su alcance. Sin embargo, daría como resultado un código más claro aquí porque puede anidar la instrucción using en el foreach.

EDIT: Como se señaló en otra respuesta, ManagementObjectCollection implementa también IDisposable por lo que han añadido que en un bloque using.

No es necesario colocar ManagementObjectCollection en una declaración using. el foreach llamará al Dispose() en el enumerador.

+0

Creo método Dispose ha ser invocada por un sitio donde "número" objeto donde crearon – Arseny

+0

No, Eliminar, se puede llamar en cualquier lugar. –

+1

foreach llama automáticamente a Dispose on Enumerable si es IDisposable, por lo que primero se usa innecesariamente – Alexander

-1

Se verá raro, iterando sobre la matriz y desechando cada uno de los objetos que contiene. Si realmente quieres hacer esto, utilizar

foreach (ManagementObject result in results) 
{ 
    try { 
     // code here 
    } 
    finally { 
     result.Dispose(); 
    } 
} 

/* do not forget to, or to not reuse results! 
results = null; 
results.Clear(); 
*/ 

que es exactamente lo que hace using comunicado.

+1

Porque esto es "exactamente lo que hace una sentencia using" es por qué no debería hacer esto. – CertifiedCrazy

2

ManagementObjectCollection es en sí mismo IDisposable ...

por lo que sería ...

using (var results = ..) 
{ 
    foreach (var result in results) 
    { 
     using (result) 
     { 
      ... 
     } 
    } 
} 
+1

Esto no llamaría a Dispose() en cada 'ManagementObject', solo en el' ManagementObjectCollection'. –

+0

Para ser muy análogo llamaría a 'Dispose' tanto en' ManagementObjectCollection' como en 'IEnumerator' utilizado en el ciclo' foreach'. –

13

Se podría hacer lo siguiente.

foreach (ManagementObject result in results) 
{ 
    using (result) 
    { 
    // Your code goes here. 
    } 
} 

Lo bueno de C# es cómo las diferentes construcciones de lenguaje pueden compartir bloques de código de ámbito. Eso significa que puede hacer lo siguiente para eliminar el anidamiento.

foreach (ManagementObject result in results) using (result) 
{ 
    // Your code goes here. 
} 

También es útil saber que el constructo foreach llamará Dispose en el objetivo IEnumerator también. El código anterior sería equivalente a.

IEnumerator enumerator = results.GetEnumerator() 
try 
{ 
    while (enumerator.MoveNext()) 
    { 
    ManagementObject result = (ManagementObject)enumerator.Current; 
    IDisposable disposable = (IDisposable)result; 
    try 
    { 
     // Your code goes here. 
    } 
    finally 
    { 
     disposable.Dispose(); 
    } 
    } 
} 
finally 
{ 
    IDisposable disposable = enumerator as IDisposable; 
    if (disposable != null) 
    { 
    disposable.Dispose(); 
    } 
} 
3

Puede obtener una buena sintaxis ordenada a través de métodos de extensión y enumeradores. En primer lugar, definir esto en un algún lugar public static class en el código:

public static IEnumerable<ManagementObject> WithDisposal(
        this ManagementObjectCollection list) 
{ 
    using (list) 
    { 
     foreach (var obj in list) 
     { 
      using (obj) 
      { 
       yield return obj; 
      } 
     } 
    } 
} 

... que luego se puede utilizar con sólo esto:

foreach (var obj in /*get the results*/.WithDisposal()) 
{ 
    // ... 
} 

A pesar de tener en cuenta que si utiliza WithDisposal entonces ganó no podrá guardar ninguno de los objetos para uso futuro.

+0

Me gusta esto. Incluso podría hacerlo genérico con restricciones de tipo para 'IDisposable'. – Chad

+1

Podría, pero este es definitivamente un caso especial. Normalmente, la eliminación de una colección de objetos desechables también debe eliminar sus objetos contenidos. (He definido una 'Lista de Desechables' genérica en mi código para este propósito.) – Miral

+1

Hay una advertencia adicional: esto solo eliminará todo si realmente atraviesa completamente la enumeración devuelta. Si te detienes a mitad de camino, la colección seguirá siendo eliminada, pero no se eliminarán los objetos que aún no hayas visto. Esto se aplica a la mayoría de las otras respuestas publicadas aquí también, por supuesto. – Miral

1

Aquí hay una sintaxis más limpia:

foreach (ManagementObject obj in result) using (obj) 
{ 
    // do your stuff here 
} 
Cuestiones relacionadas