42

I'm iterating over a ManageObjectCollection.( which is part of WMI interface).

However the important thing is, the following line of code. :

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

The point is that ManageObject also implements IDisposable, so I would like to put "result" variable in a using block. Any idea on how to do this, without getting too weird or complex?

David Neale
  • 16,498
  • 6
  • 59
  • 85
apoorv020
  • 5,420
  • 11
  • 40
  • 63

6 Answers6

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

It's not normally good practice to assign the variable outside the using block because the resource would be disposed but could stay in scope. It would, however, result in clearer code here because you can nested the using statement against the foreach.

EDIT: As pointed out in another answer, ManagementObjectCollection also implements IDisposable so I have added that into a using block.

No need to place ManagementObjectCollection in a using statement. the foreach will call Dispose() on the enumerator.

David Neale
  • 16,498
  • 6
  • 59
  • 85
  • I think Dispose method has be invoked by a site where "result" object where created – Arseny Jun 09 '10 at 11:24
  • No, Dispose can be called anywhere. – Cylon Cat Jun 09 '10 at 11:47
  • 2
    foreach automatically call Dispose on Enumerable if it is IDisposable, so first using unnecessary – Alexander Jun 06 '13 at 05:28
  • 3
    @Alexander foreach will call Dispose on the Enumerator which would be returned by ManagementObjectCollection GetEnumerator() method. Dispose will NOT be called on ManagementObjectCollection object. – Edward Olamisan Oct 23 '13 at 19:29
  • What will happen if //Code here throws an exception?! all the remaining objects in results will not be Disposed, and you have a memory leak!! – ALX May 18 '17 at 08:34
23

You could do the following.

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

The neat thing about C# is how different language constructs can share scoped code blocks. That means you could do the following to eliminate the nesting.

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

It is also useful to know that the foreach construct will call Dispose on the target IEnumerator as well. The code above would be equivalent to.

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();
  }
}
Brian Gideon
  • 47,849
  • 13
  • 107
  • 150
7

Here's a cleaner syntax:

foreach (ManagementObject obj in result) using (obj)
{
  // do your stuff here
}
Uri Abramson
  • 6,005
  • 6
  • 40
  • 62
  • 2
    I like the syntax but Visual Studio screws up the formatting (it adds an extra tab to the block). – Mark Dec 28 '21 at 21:54
4

ManagementObjectCollection is itself IDisposable...

So it would be...

using (var results = ..)
{
    foreach (var result in results)
    {
        using (result)
        {
            ...
        }
    }
}
Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
  • 1
    This would not call Dispose() on each `ManagementObject`, only on the `ManagementObjectCollection` itself. – David Neale Jun 09 '10 at 11:35
  • To be very padantic it would call `Dispose` on both the `ManagementObjectCollection` and the `IEnumerator` used in the `foreach` loop. – Brian Gideon Jun 09 '10 at 13:02
4

You can get a nice neat syntax via extension methods and enumerators. First, define this in a public static class somewhere in your code:

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

... which you can then use with just this:

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

Though bear in mind that if you use WithDisposal then you won't be able to save any of the objects for future use.

Miral
  • 12,637
  • 4
  • 53
  • 93
  • I like this. You could even make it generic with type constraints to `IDisposable`. – Chad Apr 11 '13 at 19:09
  • 1
    You could, but this is definitely a special case. Normally disposing a collection of disposable objects should dispose of its contained objects too. (I've defined a generic `DisposableList` in my code for this purpose.) – Miral Apr 12 '13 at 02:44
  • 1
    There is one further caveat -- this will only dispose everything if you actually fully traverse the enumeration returned. If you stop partway through then the collection will still be disposed but any objects you haven't looked at yet will not be. This applies to most of the other answers posted here as well, of course. – Miral Jun 05 '13 at 07:20
-1

It will look weird - iterating over array and disposing each of the objects it contains. If you really want to do this, use

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

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

which is exactly what using statement does.

nothrow
  • 15,882
  • 9
  • 57
  • 104