Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Stack Overflow when Disposing a Managed Resource

I have a simple wrapper for a Unity IoC container (a temporary use of Service Locator [anti-]Pattern to introduce DI to a legacy codebase), and since the IUnityContainer in Unity implements IDisposable I wanted to expose that through the wrapper as well.

The wrapper is simple enough:

public class IoCContainer : IIoCContainer
{
    private IUnityContainer _container;

    public IoCContainer(IUnityContainer container)
    {
        _container = container;
    }

    public T Resolve<T>()
    {
        return _container.Resolve<T>();
    }

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

    ~IoCContainer()
    {
        Dispose(false);
    }

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

IIoCContainer is the domain interface which has nothing but T Resolve<T>() on it, and of course IDisposable. So everything below that one method is simply the implementation of IDisposable as I found it on MSDN.

However, when .Dispose() is called on this object (such as when exiting a using block), a StackOverflowException is raised. Debugging, it looks like the call stack repeats between:

  • Dispose() is called on this class
  • Which calls Dispose(true) on this class
  • Which calls Dispose() on IUnityContainer
  • Which calls Dispose() on this class

enter image description here

I can resolve this in this case by putting a bool flag on the class, setting it on the first line of Dispose(), and checking for it in Dispose(bool), so the recursion ends at its second iteration. But why does this happen in the first place? I can only assume I've either missed something obvious or misunderstood something about resource disposal. But what?

like image 339
David Avatar asked Dec 22 '16 15:12

David


3 Answers

This is implementation of IDisposable within UnityContainer. It is obvious that you cannot dispose your parent container. It will iterate through all registrations and dispose them if they are also IDisposable. Take a look:

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

           if (parent != null && parent.lifetimeContainer != null) 
           { 
               parent.lifetimeContainer.Remove(this); 
           } 
       } 

       extensions.OfType<IDisposable>().ForEach(ex => ex.Dispose()); 
       extensions.Clear(); 
   } 
} 
like image 168
Johnny Avatar answered Nov 06 '22 01:11

Johnny


I believe the problem here is that you are not supposed to be disposing of the container instance that implements IUnityContainer within your class.

The instance is being passed on as a resource to your class, but it was created externally, so whatever code created that instance is the one that should be in charge of disposing of it properly.

Your IoCContainer should only be concerned with disposing of resources it creates internally.

like image 20
JuanR Avatar answered Nov 06 '22 00:11

JuanR


This is not the best answer probably, but if you have no controll over implementation of IUnityContainer and it have to dispose IoCContainer you can always break the chain of recurrection in at least two, valid ways:

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

or

private bool isDisposed = false;
protected virtual void Dispose(bool disposing)
{
    if(isDisposed) return;
    isDisposed = true;

    if (disposing)
        if (_container != null)
        {
            _container.Dispose();
            _container = null;
        }
}
like image 30
Mateusz Krzaczek Avatar answered Nov 06 '22 00:11

Mateusz Krzaczek