1

My understanding is that if an object that implements IDisposable pattern is called within a foreach loop, its got disposed automatically without need to use it in a using or calling Dispose method explicitly. I have following code

class Program
{
    static void Main(string[] args)
    {
        using (Employee e = new Employee() { Name = "John" }) ;
        {

        }

        foreach (var e in GetEmployees())
            Console.WriteLine(e.Name);
    }

    static List<Employee> GetEmployees()
    {
        Employee emp = new Employee() { Name = "Peter" };
        Employee emp2 = new Employee() { Name = "Smith" };
        List<Employee> emps = new List<Employee>();
        emps.Add(emp);
        emps.Add(emp2);
        return emps;
    }
}

class Employee : IDisposable
{
    public string Name { get; set; }

    public void Dispose()
    {
        Console.WriteLine("disposing " + Name);
    }
}

I don't see Dispose is called for objects returned by GetEmployees method. Does it mean I need to call Dispose within foreach loop?

VMAtm
  • 27,943
  • 17
  • 79
  • 125
whoami
  • 1,689
  • 3
  • 22
  • 45
  • You're not calling Dispose. So Dispose isn't getting called. – J. Steen Mar 12 '15 at 12:48
  • 1
    In a word, yes. `foreach` does not expect the items it iterates over to be disposable and therefore can not and does not dispose of them. – juharr Mar 12 '15 at 12:48
  • 4
    _"My understanding is that if an object that implements IDisposable pattern is called within a foreach loop, its got disposed automatically without need to use it in a using or calling Dispose method explicitly"_ Your understanding is wrong. Replace the "without need to" with "if you" and you're right. – Tim Schmelter Mar 12 '15 at 12:53
  • `foreach` doesn't do the `Dispose`, `using` does. – VMAtm Mar 12 '15 at 12:55
  • 1
    @johnsmith `foreach` really calls `Dispose` but only on the `IEnumerator`-like object that is used to enumerate over the collection - http://stackoverflow.com/questions/4982396/does-foreach-automatically-call-dispose – Eugene Podskal Mar 12 '15 at 13:04
  • 2
    Why do you need to dispose employees at all? I think you are misunderstanding disposing. Use it only if your class uses [unmanaged resources](http://stackoverflow.com/questions/3433197/what-exactly-are-unmanaged-resources). – Tim Schmelter Mar 12 '15 at 13:05
  • 1
    I am thinking you are getting Dispose, Garbage Collection and Scoping mixed up – Bernd Linde Mar 12 '15 at 13:53

2 Answers2

5

foreach doesn't call the Dispose method, only using does. using directive is just a sugar for:

try {
    // Initialize
}
finally {
    // Dispose
}

And yes, you have to write Dispose call by youself, like this:

foreach (var e in GetEmployees())
{
    Console.WriteLine(e.Name);
    e.Dispose();
}

or

foreach (var e in GetEmployees())
{
    using (e)
    {
        Console.WriteLine(e.Name);
    }
}

Consider Dispose Pattern from MSDN for better understanding way the Disposing works in .NET:

Simple use-case:

public class DisposableResourceHolder : IDisposable {

    private SafeHandle resource; // handle to a resource

    public DisposableResourceHolder(){
        this.resource = ... // allocates the resource
    }

    public void Dispose(){
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing){
        if (disposing){
            if (resource!= null) resource.Dispose();
        }
    }
}

Complex use-case with finalizible types:

public class ComplexResourceHolder : IDisposable {

    private IntPtr buffer; // unmanaged memory buffer
    private SafeHandle resource; // disposable handle to a resource

    public ComplexResourceHolder(){
        this.buffer = ... // allocates memory
        this.resource = ... // allocates the resource
    }

    protected virtual void Dispose(bool disposing){
            ReleaseBuffer(buffer); // release unmanaged memory
        if (disposing){ // release other disposable objects
            if (resource!= null) resource.Dispose();
        }
    }

    ~ ComplexResourceHolder(){
        Dispose(false);
    }

    public void Dispose(){
        Dispose(true);
        GC.SuppressFinalize(this);
    }
}

Update: As in comments noted, I think that you are mixing up the Garbage Collection and Disposing. Disposing is used for freeing up the unmanaged resources outside the .NET Framework in your application. Garbage Collection is done automatically and you should not force it until you have completely understanding why do you need it.

VMAtm
  • 27,943
  • 17
  • 79
  • 125
2

You have to either call Dispose() manually, or use the using() statement

rducom
  • 7,072
  • 1
  • 25
  • 39
  • how can i call using within that foreach loop? – whoami Mar 12 '15 at 12:50
  • @johnsmith `using(e) { Console.WriteLine(e.Name); }` – juharr Mar 12 '15 at 12:51
  • 4
    @johnsmith You almost certainly shouldn't be doing that. The point of `IDisposable`/`using` is that it *always* gets cleaned up appropriately. Putting your `using` inside the loop means that if any iteration of the loop throws an exception, only that item gets disposed, the remaining items won't. –  Mar 12 '15 at 12:53
  • @hvd Can you clarify what I shouldn't be doing? Calling Dispose on object in a loop or use of using in a loop? – whoami Mar 12 '15 at 13:00
  • @johnsmith `GetEmployees()` returns a number of disposable objects, so the `Dispose()` should be somewhere where it is guaranteed to be called if `GetEmployees()` returns normally. I think the best way here would be `var employees = GetEmployees(); try { foreach (var employee in employees) { ... } } finally { foreach (var employee in employees) { if (employee != null) employee.Dispose(); } } }` It's still in a loop, and it's not inherently a problem that it's in a loop, the problem was that it wasn't guaranteed to get called in all cases where you might want it to get called. –  Mar 12 '15 at 13:45
  • @johnsmith Even better would be to not return `List` in the first place. A `DisposableList where T : IDisposable` that handles the disposing of its elements internally means the caller can simply do: `using (var employees = GetEmployees()) foreach (var employee in employees) { ... }`. –  Mar 12 '15 at 13:46