2010-06-09 10 views
24

Je suis en train d'itérer sur un ManageObjectCollection (qui fait partie de l'interface WMI).Combinaison de foreach et utilisation de

Cependant, la chose importante est la ligne de code suivante. :

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

Le point est que ManageObject met également en œuvre IDisposable, donc je voudrais mettre variable « résultat » dans un bloc à l'aide. Toute idée sur la façon de le faire, sans devenir trop bizarre ou complexe?

Répondre

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

Ce n'est pas normalement de bonnes pratiques pour assigner la variable en dehors du bloc using car la ressource serait disposé, mais pourrait rester à portée. Cela entraînerait cependant un code plus clair car vous pouvez imbriquer l'instruction using par rapport à la foreach.

EDIT: Comme indiqué dans une autre réponse, ManagementObjectCollection met également en œuvre IDisposable j'ai donc ajouté que dans un bloc using.

Pas besoin de placer ManagementObjectCollection dans une instruction using. le foreach appellera Dispose() sur l'énumérateur.

+0

Je pense que la méthode Dispose a être invoqué par un site où l'objet « résultat » où créé – Arseny

+0

Non, Jeter peut être appelé partout. –

+1

foreach appelle automatiquement Dispose sur Enumerable s'il est IDisposable, donc d'abord en utilisant inutile – Alexander

-1

Cela semblera bizarre - itérer sur le tableau et disposer chacun des objets qu'il contient. Si vous voulez vraiment faire cela, utilisez

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

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

qui est exactement ce que fait la déclaration using.

+1

Parce que c'est "exactement ce que fait une instruction using" c'est pourquoi vous ne devriez pas faire cela. – CertifiedCrazy

2

ManagementObjectCollection est lui-même IDisposable ...

Il serait donc ...

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

Cela n'appellerait pas Dispose() sur chaque 'ManagementObject', seulement sur' ManagementObjectCollection' lui-même. –

+0

Pour être très padantique, il appelle 'Dispose' à la fois sur' ManagementObjectCollection' et 'IEnumerator' utilisé dans la boucle' foreach'. –

13

Vous pouvez faire ce qui suit. La chose la plus intéressante à propos de C# est de savoir comment différentes constructions de langage peuvent partager des blocs de code de portée. Cela signifie que vous pourriez faire ce qui suit pour éliminer l'imbrication.

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

Il est également utile de savoir que la construction foreach appellera Dispose sur la cible IEnumerator ainsi. Le code ci-dessus serait équivalent à.

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

Vous pouvez obtenir une bonne syntaxe via les méthodes d'extension et les énumérateurs. Tout d'abord, définir ce dans un endroit public static class dans votre code:

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

... que vous pouvez utiliser avec ceci:

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

ours Bien à l'esprit que si vous utilisez WithDisposal alors vous avez gagné ne pourrez sauvegarder aucun des objets pour une utilisation future.

+0

J'aime ça. Vous pouvez même le rendre générique avec des contraintes de type 'IDisposable'. – Chad

+1

Vous pourriez, mais c'est certainement un cas particulier. Normalement, disposer d'une collection d'objets jetables doit également disposer de ses objets contenus. (J'ai défini un 'DisposableList' générique dans mon code à cette fin.) – Miral

+1

Il y a une autre mise en garde - ceci ne disposera que de tout si vous parcourez réellement l'énumération retournée. Si vous arrêtez à mi-chemin, la collection sera toujours éliminée, mais tous les objets que vous n'avez pas encore regardés ne le seront pas. Ceci s'applique à la plupart des autres réponses affichées ici, bien sûr. – Miral

1

est ici une syntaxe plus propre:

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