From 75f2cc93163e475863a5280641b337340663a813 Mon Sep 17 00:00:00 2001 From: Simon Gockner Date: Wed, 13 Nov 2019 16:12:07 +0100 Subject: [PATCH] - 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 --- LightweightIocContainer/IocContainer.cs | 18 +++-- .../IocContainerRecursionTest.cs | 67 +++++++++++++++++-- 2 files changed, 74 insertions(+), 11 deletions(-) diff --git a/LightweightIocContainer/IocContainer.cs b/LightweightIocContainer/IocContainer.cs index f828caf..0112cfd 100644 --- a/LightweightIocContainer/IocContainer.cs +++ b/LightweightIocContainer/IocContainer.cs @@ -207,25 +207,31 @@ namespace LightweightIocContainer 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 + T resolvedInstance; + if (registration is IUnitTestCallbackRegistration unitTestCallbackRegistration) { - return unitTestCallbackRegistration.UnitTestResolveCallback.Invoke(arguments); + resolvedInstance = unitTestCallbackRegistration.UnitTestResolveCallback.Invoke(arguments); } else if (registration is IDefaultRegistration defaultRegistration) { if (defaultRegistration.Lifestyle == Lifestyle.Singleton) - return GetOrCreateSingletonInstance(defaultRegistration, arguments, resolveStack); + resolvedInstance = GetOrCreateSingletonInstance(defaultRegistration, arguments, resolveStack); else if (defaultRegistration is IMultitonRegistration multitonRegistration && defaultRegistration.Lifestyle == Lifestyle.Multiton) - return GetOrCreateMultitonInstance(multitonRegistration, arguments, resolveStack); - - return CreateInstance(defaultRegistration, arguments, resolveStack); + resolvedInstance = GetOrCreateMultitonInstance(multitonRegistration, arguments, resolveStack); + else + resolvedInstance = CreateInstance(defaultRegistration, arguments, resolveStack); } else if (registration is ITypedFactoryRegistration typedFactoryRegistration) { - return typedFactoryRegistration.Factory.Factory; + resolvedInstance = typedFactoryRegistration.Factory.Factory; } else 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; } /// diff --git a/Test.LightweightIocContainer/IocContainerRecursionTest.cs b/Test.LightweightIocContainer/IocContainerRecursionTest.cs index 3b1df3d..c14f189 100644 --- a/Test.LightweightIocContainer/IocContainerRecursionTest.cs +++ b/Test.LightweightIocContainer/IocContainerRecursionTest.cs @@ -14,7 +14,7 @@ namespace Test.LightweightIocContainer [TestFixture] public class IocContainerRecursionTest { - #region TestClasses + #region TestClassesCircularDependency [UsedImplicitly] 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() { _iocContainer = new IocContainer(); - - _iocContainer.Register(); - _iocContainer.Register(); } [TearDown] @@ -68,6 +109,9 @@ namespace Test.LightweightIocContainer [Test] public void TestCircularDependencies() { + _iocContainer.Register(); + _iocContainer.Register(); + CircularDependencyException exception = Assert.Throws(() => _iocContainer.Resolve()); Assert.AreEqual(typeof(IFoo), exception.ResolvingType); Assert.AreEqual(2, exception.ResolveStack.Count); @@ -81,9 +125,22 @@ namespace Test.LightweightIocContainer Assert.AreEqual(message, exception.Message); } + [Test] + public void TestNonCircularDependencies() + { + _iocContainer.Register(); + _iocContainer.Register(); + _iocContainer.Register(); + + IA a = _iocContainer.Resolve(); + } + [Test] public void TestRecursionWithParam() { + _iocContainer.Register(); + _iocContainer.Register(); + Assert.DoesNotThrow(() => _iocContainer.Resolve(new Mock().Object)); Assert.DoesNotThrow(() => _iocContainer.Resolve(new Mock().Object)); }