Stack overflow when deleting a managed resource

I have a simple wrapper for the Unity IoC container (temporarily using the Service Locator [anti-] template to inject DI into an outdated codebase), and since IUnityContainer in Unity implements IDisposable , I wanted to expose this also through the wrapper.

The wrapper is quite simple:

 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 a domain interface on which there is nothing but T Resolve<T>() , and, of course, IDisposable . So, everything below this method is just an implementation of IDisposable as I found it on MSDN .

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

  • Dispose() is called in this class
  • What causes Dispose(true) in this class
  • What causes Dispose() on an IUnityContainer
  • What causes Dispose() in this class

enter image description here

I can resolve this in this case by placing the bool flag in the class, setting it to the first line of Dispose() and checking it in Dispose(bool) , so the recursion ends in the second iteration. But why does this happen in the first place? I can only assume that I either missed something obvious or misunderstood something about recycling resources. But what?

+6
source share
3 answers

This is an implementation of IDisposable inside UnityContainer . Obviously, you cannot dispose of your parent container. It will go through all registrations and delete 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(); } } 
+4
source

I believe the problem is that you should not get rid of the container instance that implements the IUnityContainer inside your class.

An instance is passed as a resource to your class, but it is created externally, so any code created by this instance is the one that must properly manage it.

Your IoCContainer should only be associated with deleting the resources that it creates internally.

+1
source

This is probably not the best answer, but if you have no control over the implementation of IUnityContainer and need to manage the IoCContainer , you can always break the retry chain 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; } } 
+1
source

Source: https://habr.com/ru/post/1013427/


All Articles