2010-06-09 16 views
24

Sto iterando su ManageObjectCollection. (Che fa parte dell'interfaccia WMI).Combinare foreach e utilizzare

Tuttavia, la cosa importante è la seguente riga di codice. :

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

Il punto è che ManageObject implementa anche IDisposable, così desidero mettere variabile "risultato" in un blocco utilizzando. Qualche idea su come fare questo, senza diventare troppo strano o complesso?

risposta

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

Non è normalmente buona pratica assegnare la variabile all'esterno del blocco using perché la risorsa sarà smaltito ma potrebbe rimanere nella portata. Sarebbe, tuttavia, risultato qui un codice più chiaro perché è possibile annidare l'istruzione using rispetto allo foreach.

EDIT: Come sottolineato in un'altra risposta, ManagementObjectCollection implementa anche IDisposable così ho aggiunto che in un blocco using.

Non è necessario inserire ManagementObjectCollection in una dichiarazione using. lo foreach chiamerà Dispose() sull'enumeratore.

+0

Penso metodo Dispose è essere invocata da un sito in cui oggetto "risultato", dove ha creato – Arseny

+0

No, lo smaltimento può essere chiamato da nessuna parte. –

+1

foreach chiama automaticamente Dispose su Enumerable se è IDisposable, quindi prima utilizza inutili – Alexander

-1

Sembrerà strano, iterando su un array e smaltendo ciascuno degli oggetti in esso contenuti. Se si vuole veramente fare questo, utilizzare

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

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

che è esattamente ciò using dichiarazione fa.

+1

Poiché questo è "esattamente ciò che fa un'istruzione using" è il motivo per cui non dovresti farlo. – CertifiedCrazy

2

ManagementObjectCollection è di per sé IDisposable ...

quindi sarebbe ...

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

Questo non chiamerebbe Dispose() su ciascun 'ManagementObject', solo sul 'ManagementObjectCollection' stesso. –

+0

Per essere molto poderoso chiamerebbe 'Dispose' su' ManagementObjectCollection' e 'IEnumerator' usato nel ciclo' foreach'. –

13

Si potrebbe fare quanto segue.

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

La particolarità di C# è il modo in cui i diversi costrutti del linguaggio possono condividere blocchi di codice con scope. Ciò significa che puoi fare quanto segue per eliminare il nidificazione.

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

E 'anche utile sapere che il costrutto foreach chiamerà Dispose sul bersaglio IEnumerator pure. Il codice sopra sarebbe 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

È possibile ottenere una sintassi accurata tramite i metodi di estensione e gli enumeratori. In primo luogo, definire questo in un public static class da qualche parte nel codice:

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

... che è quindi possibile utilizzare con proprio questo:

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

Anche se tenere a mente che se si utilizza WithDisposal allora si vince essere in grado di salvare qualsiasi oggetto per un uso futuro.

+0

Mi piace questo. Si potrebbe persino renderlo generico con vincoli di tipo a 'IDisposable'. – Chad

+1

Si potrebbe, ma questo è sicuramente un caso speciale. Lo smaltimento di una raccolta di oggetti usa e getta normalmente deve essere eliminato anche dagli oggetti contenuti. (Ho definito un generico 'DisposableList' nel mio codice per questo scopo.) – Miral

+1

C'è un'ulteriore avvertenza - questo disporrà tutto solo se si attraversa completamente l'enumerazione restituita. Se ti fermi a metà strada, la raccolta verrà comunque eliminata, ma gli oggetti che non hai ancora guardato non saranno. Questo vale anche per la maggior parte delle altre risposte pubblicate qui, ovviamente. – Miral

1

Ecco una sintassi più pulito:

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