- fix circular dependency check:

- remove successfully resolved objects from the resolve stack
  - add special test case that checks for a situation where this could be wrong
pull/32/head
Simon Gockner 6 years ago
parent c86f604ec3
commit 75f2cc9316
  1. 18
      LightweightIocContainer/IocContainer.cs
  2. 67
      Test.LightweightIocContainer/IocContainerRecursionTest.cs

@ -207,25 +207,31 @@ namespace LightweightIocContainer
else //not the first resolve call in chain but no circular dependencies for now else //not the first resolve call in chain but no circular dependencies for now
resolveStack.Add(typeof(T)); //add currently resolving type to the stack resolveStack.Add(typeof(T)); //add currently resolving type to the stack
T resolvedInstance;
if (registration is IUnitTestCallbackRegistration<T> unitTestCallbackRegistration) if (registration is IUnitTestCallbackRegistration<T> unitTestCallbackRegistration)
{ {
return unitTestCallbackRegistration.UnitTestResolveCallback.Invoke(arguments); resolvedInstance = unitTestCallbackRegistration.UnitTestResolveCallback.Invoke(arguments);
} }
else if (registration is IDefaultRegistration<T> defaultRegistration) else if (registration is IDefaultRegistration<T> defaultRegistration)
{ {
if (defaultRegistration.Lifestyle == Lifestyle.Singleton) if (defaultRegistration.Lifestyle == Lifestyle.Singleton)
return GetOrCreateSingletonInstance(defaultRegistration, arguments, resolveStack); resolvedInstance = GetOrCreateSingletonInstance(defaultRegistration, arguments, resolveStack);
else if (defaultRegistration is IMultitonRegistration<T> multitonRegistration && defaultRegistration.Lifestyle == Lifestyle.Multiton) else if (defaultRegistration is IMultitonRegistration<T> multitonRegistration && defaultRegistration.Lifestyle == Lifestyle.Multiton)
return GetOrCreateMultitonInstance(multitonRegistration, arguments, resolveStack); resolvedInstance = GetOrCreateMultitonInstance(multitonRegistration, arguments, resolveStack);
else
return CreateInstance(defaultRegistration, arguments, resolveStack); resolvedInstance = CreateInstance(defaultRegistration, arguments, resolveStack);
} }
else if (registration is ITypedFactoryRegistration<T> typedFactoryRegistration) else if (registration is ITypedFactoryRegistration<T> typedFactoryRegistration)
{ {
return typedFactoryRegistration.Factory.Factory; resolvedInstance = typedFactoryRegistration.Factory.Factory;
} }
else else
throw new UnknownRegistrationException($"There is no registration of type {registration.GetType().Name}."); throw new UnknownRegistrationException($"There is no registration of type {registration.GetType().Name}.");
resolveStack.Remove(typeof(T)); //T was successfully resolved -> no circular dependency -> remove from resolve stack
return resolvedInstance;
} }
/// <summary> /// <summary>

@ -14,7 +14,7 @@ namespace Test.LightweightIocContainer
[TestFixture] [TestFixture]
public class IocContainerRecursionTest public class IocContainerRecursionTest
{ {
#region TestClasses #region TestClassesCircularDependency
[UsedImplicitly] [UsedImplicitly]
public interface IFoo public interface IFoo
@ -44,7 +44,51 @@ namespace Test.LightweightIocContainer
} }
} }
#endregion TestClasses #endregion TestClassesCircularDependency
#region TestClassesNonCircularDependency
[UsedImplicitly]
public interface IA
{
}
[UsedImplicitly]
public interface IB
{
}
[UsedImplicitly]
public interface IC
{
}
[UsedImplicitly]
private class A : IA
{
public A(IB b, IC c)
{
}
}
[UsedImplicitly]
private class B : IB
{
public B(IC c)
{
}
}
[UsedImplicitly]
private class C : IC
{
}
#endregion TestClassesNonCircularDependency
@ -54,9 +98,6 @@ namespace Test.LightweightIocContainer
public void SetUp() public void SetUp()
{ {
_iocContainer = new IocContainer(); _iocContainer = new IocContainer();
_iocContainer.Register<IFoo, Foo>();
_iocContainer.Register<IBar, Bar>();
} }
[TearDown] [TearDown]
@ -68,6 +109,9 @@ namespace Test.LightweightIocContainer
[Test] [Test]
public void TestCircularDependencies() public void TestCircularDependencies()
{ {
_iocContainer.Register<IFoo, Foo>();
_iocContainer.Register<IBar, Bar>();
CircularDependencyException exception = Assert.Throws<CircularDependencyException>(() => _iocContainer.Resolve<IFoo>()); CircularDependencyException exception = Assert.Throws<CircularDependencyException>(() => _iocContainer.Resolve<IFoo>());
Assert.AreEqual(typeof(IFoo), exception.ResolvingType); Assert.AreEqual(typeof(IFoo), exception.ResolvingType);
Assert.AreEqual(2, exception.ResolveStack.Count); Assert.AreEqual(2, exception.ResolveStack.Count);
@ -81,9 +125,22 @@ namespace Test.LightweightIocContainer
Assert.AreEqual(message, exception.Message); Assert.AreEqual(message, exception.Message);
} }
[Test]
public void TestNonCircularDependencies()
{
_iocContainer.Register<IA, A>();
_iocContainer.Register<IB, B>();
_iocContainer.Register<IC, C>();
IA a = _iocContainer.Resolve<IA>();
}
[Test] [Test]
public void TestRecursionWithParam() public void TestRecursionWithParam()
{ {
_iocContainer.Register<IFoo, Foo>();
_iocContainer.Register<IBar, Bar>();
Assert.DoesNotThrow(() => _iocContainer.Resolve<IFoo>(new Mock<IBar>().Object)); Assert.DoesNotThrow(() => _iocContainer.Resolve<IFoo>(new Mock<IBar>().Object));
Assert.DoesNotThrow(() => _iocContainer.Resolve<IBar>(new Mock<IFoo>().Object)); Assert.DoesNotThrow(() => _iocContainer.Resolve<IBar>(new Mock<IFoo>().Object));
} }

Loading…
Cancel
Save