diff --git a/LightweightIocContainer/Exceptions/IllegalAbstractMethodCreationException.cs b/LightweightIocContainer/Exceptions/IllegalAbstractMethodCreationException.cs new file mode 100644 index 0000000..88034cf --- /dev/null +++ b/LightweightIocContainer/Exceptions/IllegalAbstractMethodCreationException.cs @@ -0,0 +1,26 @@ +// // Author: Gockner, Simon +// // Created: 2019-06-28 +// // Copyright(c) 2019 SimonG. All Rights Reserved. + +using System; +using System.Reflection; + +namespace LightweightIocContainer.Exceptions +{ + /// + /// The creation of the abstract method is illegal in its current state + /// + public class IllegalAbstractMethodCreationException : Exception + { + public IllegalAbstractMethodCreationException(string message, MethodInfo method) + : base(message) + { + Method = method; + } + + /// + /// The Method whose creation is illegal + /// + public MethodInfo Method { get; } + } +} \ No newline at end of file diff --git a/LightweightIocContainer/Interfaces/IIocContainer.cs b/LightweightIocContainer/Interfaces/IIocContainer.cs index f18b469..ff23b00 100644 --- a/LightweightIocContainer/Interfaces/IIocContainer.cs +++ b/LightweightIocContainer/Interfaces/IIocContainer.cs @@ -51,5 +51,11 @@ namespace LightweightIocContainer.Interfaces /// An instance of the given type /// Could not find function object Resolve(Type type, object[] arguments); + + /// + /// Clear the multiton instances of the given type from the registered multitons list + /// + /// The Type to clear the multiton instances + void ClearMultitonInstances(); } } \ No newline at end of file diff --git a/LightweightIocContainer/IocContainer.cs b/LightweightIocContainer/IocContainer.cs index d3d3cf9..7009119 100644 --- a/LightweightIocContainer/IocContainer.cs +++ b/LightweightIocContainer/IocContainer.cs @@ -158,7 +158,7 @@ namespace LightweightIocContainer throw new MultitonResolveException("Can not resolve multiton without arguments.", typeof(T)); object scopeArgument = arguments[0]; - if (scopeArgument.GetType() != registration.Scope) + if (scopeArgument.GetType() != registration.Scope && !registration.Scope.IsInstanceOfType(scopeArgument)) throw new MultitonResolveException($"Can not resolve multiton without the first argument being the scope (should be of type {registration.Scope}).", typeof(T)); //if a multiton for the given scope exists return it @@ -245,7 +245,22 @@ namespace LightweightIocContainer return null; } - + + /// + /// Clear the multiton instances of the given type from the registered multitons list + /// + /// The Type to clear the multiton instances + public void ClearMultitonInstances() + { + var multitonInstance = _multitons.FirstOrDefault(m => m.type == typeof(T)); + + //it is allowed to clear a non existing multiton instance (don't throw an exception) + if (multitonInstance == default) + return; + + _multitons.Remove(multitonInstance); + } + public void Dispose() { _registrations.Clear(); diff --git a/LightweightIocContainer/LightweightIocContainer.xml b/LightweightIocContainer/LightweightIocContainer.xml index dd41291..71c031c 100644 --- a/LightweightIocContainer/LightweightIocContainer.xml +++ b/LightweightIocContainer/LightweightIocContainer.xml @@ -4,6 +4,16 @@ LightweightIocContainer + + + The creation of the abstract method is illegal in its current state + + + + + The Method whose creation is illegal + + An internal Error happened while the tried to resolve an instance @@ -153,6 +163,12 @@ An instance of the given type Could not find function + + + Clear the multiton instances of the given type from the registered multitons list + + The Type to clear the multiton instances + An that installs all s for its given @@ -330,6 +346,12 @@ The existing arguments An array of all needed constructor arguments to create + + + Clear the multiton instances of the given type from the registered multitons list + + The Type to clear the multiton instances + The Lifestyles that can be used for a @@ -483,6 +505,7 @@ Creates the factory from the given abstract factory type Factory registration is invalid + Creation of abstract methods are illegal in their current state diff --git a/LightweightIocContainer/Registrations/TypedFactoryRegistration.cs b/LightweightIocContainer/Registrations/TypedFactoryRegistration.cs index ee3d1d1..e85de8c 100644 --- a/LightweightIocContainer/Registrations/TypedFactoryRegistration.cs +++ b/LightweightIocContainer/Registrations/TypedFactoryRegistration.cs @@ -21,6 +21,8 @@ namespace LightweightIocContainer.Registrations /// The type of the abstract typed factory public class TypedFactoryRegistration : ITypedFactoryRegistration { + private const string CLEAR_MULTITON_INSTANCE_METHOD_NAME = "ClearMultitonInstance"; + public TypedFactoryRegistration(Type factoryType, IIocContainer container) { InterfaceType = factoryType; @@ -49,6 +51,7 @@ namespace LightweightIocContainer.Registrations /// Creates the factory from the given abstract factory type /// /// Factory registration is invalid + /// Creation of abstract methods are illegal in their current state private void CreateFactory(IIocContainer container) { List createMethods = InterfaceType.GetMethods().Where(m => m.ReturnType != typeof(void)).ToList(); @@ -129,6 +132,41 @@ namespace LightweightIocContainer.Registrations generator.Emit(OpCodes.Ret); } + //if factory contains a method to clear multiton instances + MethodInfo multitonClearMethod = InterfaceType.GetMethods().FirstOrDefault(m => m.Name.Equals(CLEAR_MULTITON_INSTANCE_METHOD_NAME)); + if (multitonClearMethod != null) + { + //create a method that looks like this + //public void ClearMultitonInstance() + //{ + // IIocContainer.ClearMultitonInstances(); + //} + + if (multitonClearMethod.IsGenericMethod) + { + Type typeToClear = multitonClearMethod.GetGenericArguments().FirstOrDefault(); + if (typeToClear == null) + throw new IllegalAbstractMethodCreationException("No Type to clear specified.", multitonClearMethod); + + MethodBuilder multitonClearMethodBuilder = typeBuilder.DefineMethod(multitonClearMethod.Name, MethodAttributes.Public | MethodAttributes.Virtual, + multitonClearMethod.ReturnType, null); + multitonClearMethodBuilder.DefineGenericParameters(typeToClear.Name); + + typeBuilder.DefineMethodOverride(multitonClearMethodBuilder, multitonClearMethod); + + ILGenerator multitonClearGenerator = multitonClearMethodBuilder.GetILGenerator(); + multitonClearGenerator.Emit(OpCodes.Ldarg_0); + multitonClearGenerator.Emit(OpCodes.Ldfld, containerFieldBuilder); + + multitonClearGenerator.EmitCall(OpCodes.Callvirt, typeof(IIocContainer).GetMethod(nameof(IIocContainer.ClearMultitonInstances))?.MakeGenericMethod(typeToClear), null); + multitonClearGenerator.Emit(OpCodes.Ret); + } + else + { + throw new IllegalAbstractMethodCreationException("No Type to clear specified.", multitonClearMethod); + } + } + Factory.Factory = (TFactory) Activator.CreateInstance(typeBuilder.CreateTypeInfo().AsType(), container); } } diff --git a/Test.LightweightIocContainer/IocContainerTest.cs b/Test.LightweightIocContainer/IocContainerTest.cs index d9be809..13052a1 100644 --- a/Test.LightweightIocContainer/IocContainerTest.cs +++ b/Test.LightweightIocContainer/IocContainerTest.cs @@ -26,6 +26,8 @@ namespace Test.LightweightIocContainer ITest Create(); ITest Create(string name); ITest Create(MultitonScope scope); + + void ClearMultitonInstance(); } private interface ITestFactoryNoCreate @@ -33,6 +35,13 @@ namespace Test.LightweightIocContainer } + private interface ITestFactoryNonGenericClear + { + ITest Create(); + + void ClearMultitonInstance(); + } + private class Test : ITest { @@ -112,6 +121,14 @@ namespace Test.LightweightIocContainer Assert.Throws(() => iocContainer.Register(RegistrationFactory.RegisterFactory(iocContainer))); } + [Test] + public void TestRegisterFactoryClearMultitonsNonGeneric() + { + IIocContainer iocContainer = new IocContainer(); + + Assert.Throws(() => iocContainer.Register(RegistrationFactory.RegisterFactory(iocContainer))); + } + [Test] public void TestResolveNotRegistered() { @@ -287,5 +304,35 @@ namespace Test.LightweightIocContainer Assert.AreNotSame(resolvedTest1, resolvedTest3); Assert.AreNotSame(resolvedTest2, resolvedTest3); } + + [Test] + public void TestResolveMultitonFromFactoryClearInstances() + { + IIocContainer iocContainer = new IocContainer(); + iocContainer.Register(RegistrationFactory.Register()); + iocContainer.Register(RegistrationFactory.RegisterFactory(iocContainer)); + + MultitonScope scope1 = new MultitonScope(); + MultitonScope scope2 = new MultitonScope(); + + ITestFactory testFactory = iocContainer.Resolve(); + + ITest resolvedTest1 = testFactory.Create(scope1); + ITest resolvedTest2 = testFactory.Create(scope1); + ITest resolvedTest3 = testFactory.Create(scope2); + + Assert.AreSame(resolvedTest1, resolvedTest2); + Assert.AreNotSame(resolvedTest1, resolvedTest3); + Assert.AreNotSame(resolvedTest2, resolvedTest3); + + testFactory.ClearMultitonInstance(); + + ITest resolvedTest4 = testFactory.Create(scope1); + ITest resolvedTest5 = testFactory.Create(scope2); + + Assert.AreNotSame(resolvedTest1, resolvedTest4); + Assert.AreNotSame(resolvedTest2, resolvedTest4); + Assert.AreNotSame(resolvedTest3, resolvedTest5); + } } } \ No newline at end of file