Skip to content

Commit

Permalink
Fixes inner container disposing outer scope binding
Browse files Browse the repository at this point in the history
  • Loading branch information
gustavopsantos committed Dec 12, 2022
1 parent 0867f1a commit de8c737
Show file tree
Hide file tree
Showing 9 changed files with 59 additions and 18 deletions.
9 changes: 4 additions & 5 deletions Assets/Reflex.Tests/ScopedContainerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ public void DisposingInnerScopeShouldNotDisposeInstancesFromOuterScope()
inner.Resolve<DependsOnFoo>().Foo.IsDisposed.Should().BeFalse();
}

outer.Resolve<Foo>().IsDisposed.Should().BeTrue();
outer.Resolve<Foo>().IsDisposed.Should().BeFalse();
}
}

Expand Down Expand Up @@ -158,12 +158,11 @@ public void Dispose()
public void InnerScopedContainerShouldNotDisposeOuterBindings()
{
var outer = new Container("Outer");
outer.BindSingleton<IManager, Manager>();
// outer.Resolve<IManager>(); // Workaround: resolving it in here avoids it being disposed at inner
outer.BindSingleton<Foo, Foo>();
var inner = outer.Scope("Inner");
inner.Resolve<IManager>();
inner.Resolve<Foo>();
inner.Dispose();
outer.Resolve<IManager>().Disposed.Should().BeFalse();
outer.Resolve<Foo>().IsDisposed.Should().BeFalse();
}
}
}
17 changes: 12 additions & 5 deletions Assets/Reflex/Scripts/Core/Container.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
using Reflex.Injectors;
using Reflex.Scripts.Utilities;
using System.Collections.Generic;
using System.Linq;
using Reflex.Scripts.Enums;
using Reflex.Scripts.Extensions;

Expand Down Expand Up @@ -74,7 +73,9 @@ public bool Contains(Type type)

public void BindFunction<TContract>(Func<TContract> function)
{
_resolvers.Add(typeof(TContract), new FunctionResolver(function as Func<object>));
var resolver = new FunctionResolver(function as Func<object>);
_disposables.Add(resolver);
_resolvers.Add(typeof(TContract), resolver);
}

public void BindInstance(object instance)
Expand All @@ -89,17 +90,23 @@ public void BindInstanceAs<TContract>(TContract instance)

public void BindInstanceAs(object instance, Type asType)
{
_resolvers[asType] = new InstanceResolver(instance);
var resolver = new InstanceResolver(instance);
_disposables.Add(resolver);
_resolvers[asType] = resolver;
}

public void BindTransient<TContract, TConcrete>() where TConcrete : TContract
{
_resolvers[typeof(TContract)] = new TransientResolver(typeof(TConcrete));
var resolver = new TransientResolver(typeof(TConcrete));
_disposables.Add(resolver);
_resolvers[typeof(TContract)] = resolver;
}

public void BindSingleton<TContract, TConcrete>() where TConcrete : TContract
{
_resolvers[typeof(TContract)] = new SingletonResolver(typeof(TConcrete));
var resolver = new SingletonResolver(typeof(TConcrete));
_disposables.Add(resolver);
_resolvers[typeof(TContract)] = resolver;
}

public T Construct<T>()
Expand Down
4 changes: 0 additions & 4 deletions Assets/Reflex/Scripts/Injectors/ConstructorInjector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,6 @@ internal static object ConstructAndInject(Type concrete, Container container)
try
{
var instance = info.Activator(objects);
if (instance is IDisposable disposable)
{
container.AddDisposable(disposable);
}
ArrayPool<object>.Shared.Return(objects);
return instance;
}
Expand Down
5 changes: 5 additions & 0 deletions Assets/Reflex/Scripts/Resolvers/FunctionResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,10 @@ public object Resolve(Container container)
Resolutions++;
return _function.Invoke();
}

public void Dispose()
{
// Objects created by user functions, should be disposed by users
}
}
}
2 changes: 1 addition & 1 deletion Assets/Reflex/Scripts/Resolvers/IResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace Reflex
{
internal interface IResolver
internal interface IResolver : IDisposable
{
Type Concrete { get; }
int Resolutions { get; }
Expand Down
5 changes: 5 additions & 0 deletions Assets/Reflex/Scripts/Resolvers/InstanceResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,10 @@ public object Resolve(Container container)
Resolutions++;
return _instance;
}

public void Dispose()
{
// Objects created by user, should be disposed by users
}
}
}
10 changes: 9 additions & 1 deletion Assets/Reflex/Scripts/Resolvers/SingletonResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,18 @@ public SingletonResolver(Type concrete)
Concrete = concrete;
}

public void Dispose()
{
if (_instance is IDisposable disposable)
{
disposable.Dispose();
}
}

public object Resolve(Container container)
{
Resolutions++;

if (_instance == null)
{
_instance = container.Construct(Concrete);
Expand Down
18 changes: 17 additions & 1 deletion Assets/Reflex/Scripts/Resolvers/TransientResolver.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using Reflex.Injectors;

namespace Reflex
Expand All @@ -7,6 +8,7 @@ internal class TransientResolver : IResolver
{
public Type Concrete { get; }
public int Resolutions { get; private set; }
private readonly Stack<object> _instances = new Stack<object>();

public TransientResolver(Type concrete)
{
Expand All @@ -16,7 +18,21 @@ public TransientResolver(Type concrete)
public object Resolve(Container container)
{
Resolutions++;
return ConstructorInjector.ConstructAndInject(Concrete, container);
var instance = ConstructorInjector.ConstructAndInject(Concrete, container);
_instances.Push(instance);
return instance;
}

public void Dispose()
{
while (_instances.Count > 0)
{
var instance = _instances.Pop();
if (instance is IDisposable disposable)
{
disposable.Dispose();
}
}
}
}
}
7 changes: 6 additions & 1 deletion Assets/Reflex/Scripts/Utilities/CompositeDisposable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,16 @@ public class CompositeDisposable : IDisposable
{
private readonly List<IDisposable> _registry = new List<IDisposable>();

public void Add(IDisposable disposable)
{
_registry.Add(disposable);
}

public void TryAdd(object obj)
{
if (obj is IDisposable disposable)
{
_registry.Add(disposable);
Add(disposable);
}
}

Expand Down

0 comments on commit de8c737

Please sign in to comment.