#3: improve multiton usage:

- allow declaration of interfaces as scope, but still getting instance through implementation
- add new method `ClearMultitonInstances<T>()` that allows to clear the created multiton instances for a given type
- handle `ClearMultitonInstance<T>()` method in abstract factories and call the corresponding method in the IIocContainer
- update tests
pull/32/head
Simon Gockner 7 years ago
parent a1189e493f
commit 42b9eb53c9
  1. 26
      LightweightIocContainer/Exceptions/IllegalAbstractMethodCreationException.cs
  2. 6
      LightweightIocContainer/Interfaces/IIocContainer.cs
  3. 17
      LightweightIocContainer/IocContainer.cs
  4. 23
      LightweightIocContainer/LightweightIocContainer.xml
  5. 38
      LightweightIocContainer/Registrations/TypedFactoryRegistration.cs
  6. 47
      Test.LightweightIocContainer/IocContainerTest.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
{
/// <summary>
/// The creation of the abstract method is illegal in its current state
/// </summary>
public class IllegalAbstractMethodCreationException : Exception
{
public IllegalAbstractMethodCreationException(string message, MethodInfo method)
: base(message)
{
Method = method;
}
/// <summary>
/// The Method whose creation is illegal
/// </summary>
public MethodInfo Method { get; }
}
}

@ -51,5 +51,11 @@ namespace LightweightIocContainer.Interfaces
/// <returns>An instance of the given type</returns> /// <returns>An instance of the given type</returns>
/// <exception cref="InternalResolveException">Could not find function <see cref="IocContainer.ResolveInternal{T}"/></exception> /// <exception cref="InternalResolveException">Could not find function <see cref="IocContainer.ResolveInternal{T}"/></exception>
object Resolve(Type type, object[] arguments); object Resolve(Type type, object[] arguments);
/// <summary>
/// Clear the multiton instances of the given type from the registered multitons list
/// </summary>
/// <typeparam name="T">The Type to clear the multiton instances</typeparam>
void ClearMultitonInstances<T>();
} }
} }

@ -158,7 +158,7 @@ namespace LightweightIocContainer
throw new MultitonResolveException("Can not resolve multiton without arguments.", typeof(T)); throw new MultitonResolveException("Can not resolve multiton without arguments.", typeof(T));
object scopeArgument = arguments[0]; 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)); 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 //if a multiton for the given scope exists return it
@ -246,6 +246,21 @@ namespace LightweightIocContainer
return null; return null;
} }
/// <summary>
/// Clear the multiton instances of the given type from the registered multitons list
/// </summary>
/// <typeparam name="T">The Type to clear the multiton instances</typeparam>
public void ClearMultitonInstances<T>()
{
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() public void Dispose()
{ {
_registrations.Clear(); _registrations.Clear();

@ -4,6 +4,16 @@
<name>LightweightIocContainer</name> <name>LightweightIocContainer</name>
</assembly> </assembly>
<members> <members>
<member name="T:LightweightIocContainer.Exceptions.IllegalAbstractMethodCreationException">
<summary>
The creation of the abstract method is illegal in its current state
</summary>
</member>
<member name="P:LightweightIocContainer.Exceptions.IllegalAbstractMethodCreationException.Method">
<summary>
The Method whose creation is illegal
</summary>
</member>
<member name="T:LightweightIocContainer.Exceptions.InternalResolveException"> <member name="T:LightweightIocContainer.Exceptions.InternalResolveException">
<summary> <summary>
An internal Error happened while the <see cref="T:LightweightIocContainer.Interfaces.IIocContainer"/> tried to resolve an instance An internal Error happened while the <see cref="T:LightweightIocContainer.Interfaces.IIocContainer"/> tried to resolve an instance
@ -153,6 +163,12 @@
<returns>An instance of the given type</returns> <returns>An instance of the given type</returns>
<exception cref="T:LightweightIocContainer.Exceptions.InternalResolveException">Could not find function <see cref="M:LightweightIocContainer.IocContainer.ResolveInternal``1(System.Object[])"/></exception> <exception cref="T:LightweightIocContainer.Exceptions.InternalResolveException">Could not find function <see cref="M:LightweightIocContainer.IocContainer.ResolveInternal``1(System.Object[])"/></exception>
</member> </member>
<member name="M:LightweightIocContainer.Interfaces.IIocContainer.ClearMultitonInstances``1">
<summary>
Clear the multiton instances of the given type from the registered multitons list
</summary>
<typeparam name="T">The Type to clear the multiton instances</typeparam>
</member>
<member name="T:LightweightIocContainer.Interfaces.Installers.IAssemblyInstaller"> <member name="T:LightweightIocContainer.Interfaces.Installers.IAssemblyInstaller">
<summary> <summary>
An <see cref="T:LightweightIocContainer.Interfaces.Installers.IIocInstaller"/> that installs all <see cref="T:LightweightIocContainer.Interfaces.Installers.IIocInstaller"/>s for its given <see cref="T:System.Reflection.Assembly"/> An <see cref="T:LightweightIocContainer.Interfaces.Installers.IIocInstaller"/> that installs all <see cref="T:LightweightIocContainer.Interfaces.Installers.IIocInstaller"/>s for its given <see cref="T:System.Reflection.Assembly"/>
@ -330,6 +346,12 @@
<param name="arguments">The existing arguments</param> <param name="arguments">The existing arguments</param>
<returns>An array of all needed constructor arguments to create <param name="type"></param></returns> <returns>An array of all needed constructor arguments to create <param name="type"></param></returns>
</member> </member>
<member name="M:LightweightIocContainer.IocContainer.ClearMultitonInstances``1">
<summary>
Clear the multiton instances of the given type from the registered multitons list
</summary>
<typeparam name="T">The Type to clear the multiton instances</typeparam>
</member>
<member name="T:LightweightIocContainer.Lifestyle"> <member name="T:LightweightIocContainer.Lifestyle">
<summary> <summary>
The Lifestyles that can be used for a <see cref="T:LightweightIocContainer.Interfaces.Registrations.IDefaultRegistration`1"/> The Lifestyles that can be used for a <see cref="T:LightweightIocContainer.Interfaces.Registrations.IDefaultRegistration`1"/>
@ -483,6 +505,7 @@
Creates the factory from the given abstract factory type Creates the factory from the given abstract factory type
</summary> </summary>
<exception cref="T:LightweightIocContainer.Exceptions.InvalidFactoryRegistrationException">Factory registration is invalid</exception> <exception cref="T:LightweightIocContainer.Exceptions.InvalidFactoryRegistrationException">Factory registration is invalid</exception>
<exception cref="T:LightweightIocContainer.Exceptions.IllegalAbstractMethodCreationException">Creation of abstract methods are illegal in their current state</exception>
</member> </member>
</members> </members>
</doc> </doc>

@ -21,6 +21,8 @@ namespace LightweightIocContainer.Registrations
/// <typeparam name="TFactory">The type of the abstract typed factory</typeparam> /// <typeparam name="TFactory">The type of the abstract typed factory</typeparam>
public class TypedFactoryRegistration<TFactory> : ITypedFactoryRegistration<TFactory> public class TypedFactoryRegistration<TFactory> : ITypedFactoryRegistration<TFactory>
{ {
private const string CLEAR_MULTITON_INSTANCE_METHOD_NAME = "ClearMultitonInstance";
public TypedFactoryRegistration(Type factoryType, IIocContainer container) public TypedFactoryRegistration(Type factoryType, IIocContainer container)
{ {
InterfaceType = factoryType; InterfaceType = factoryType;
@ -49,6 +51,7 @@ namespace LightweightIocContainer.Registrations
/// Creates the factory from the given abstract factory type /// Creates the factory from the given abstract factory type
/// </summary> /// </summary>
/// <exception cref="InvalidFactoryRegistrationException">Factory registration is invalid</exception> /// <exception cref="InvalidFactoryRegistrationException">Factory registration is invalid</exception>
/// <exception cref="IllegalAbstractMethodCreationException">Creation of abstract methods are illegal in their current state</exception>
private void CreateFactory(IIocContainer container) private void CreateFactory(IIocContainer container)
{ {
List<MethodInfo> createMethods = InterfaceType.GetMethods().Where(m => m.ReturnType != typeof(void)).ToList(); List<MethodInfo> createMethods = InterfaceType.GetMethods().Where(m => m.ReturnType != typeof(void)).ToList();
@ -129,6 +132,41 @@ namespace LightweightIocContainer.Registrations
generator.Emit(OpCodes.Ret); 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<typeToClear>()
//{
// IIocContainer.ClearMultitonInstances<typeToClear>();
//}
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); Factory.Factory = (TFactory) Activator.CreateInstance(typeBuilder.CreateTypeInfo().AsType(), container);
} }
} }

@ -26,6 +26,8 @@ namespace Test.LightweightIocContainer
ITest Create(); ITest Create();
ITest Create(string name); ITest Create(string name);
ITest Create(MultitonScope scope); ITest Create(MultitonScope scope);
void ClearMultitonInstance<T>();
} }
private interface ITestFactoryNoCreate private interface ITestFactoryNoCreate
@ -33,6 +35,13 @@ namespace Test.LightweightIocContainer
} }
private interface ITestFactoryNonGenericClear
{
ITest Create();
void ClearMultitonInstance();
}
private class Test : ITest private class Test : ITest
{ {
@ -112,6 +121,14 @@ namespace Test.LightweightIocContainer
Assert.Throws<InvalidFactoryRegistrationException>(() => iocContainer.Register(RegistrationFactory.RegisterFactory<ITestFactoryNoCreate>(iocContainer))); Assert.Throws<InvalidFactoryRegistrationException>(() => iocContainer.Register(RegistrationFactory.RegisterFactory<ITestFactoryNoCreate>(iocContainer)));
} }
[Test]
public void TestRegisterFactoryClearMultitonsNonGeneric()
{
IIocContainer iocContainer = new IocContainer();
Assert.Throws<IllegalAbstractMethodCreationException>(() => iocContainer.Register(RegistrationFactory.RegisterFactory<ITestFactoryNonGenericClear>(iocContainer)));
}
[Test] [Test]
public void TestResolveNotRegistered() public void TestResolveNotRegistered()
{ {
@ -287,5 +304,35 @@ namespace Test.LightweightIocContainer
Assert.AreNotSame(resolvedTest1, resolvedTest3); Assert.AreNotSame(resolvedTest1, resolvedTest3);
Assert.AreNotSame(resolvedTest2, resolvedTest3); Assert.AreNotSame(resolvedTest2, resolvedTest3);
} }
[Test]
public void TestResolveMultitonFromFactoryClearInstances()
{
IIocContainer iocContainer = new IocContainer();
iocContainer.Register(RegistrationFactory.Register<ITest, Test, MultitonScope>());
iocContainer.Register(RegistrationFactory.RegisterFactory<ITestFactory>(iocContainer));
MultitonScope scope1 = new MultitonScope();
MultitonScope scope2 = new MultitonScope();
ITestFactory testFactory = iocContainer.Resolve<ITestFactory>();
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>();
ITest resolvedTest4 = testFactory.Create(scope1);
ITest resolvedTest5 = testFactory.Create(scope2);
Assert.AreNotSame(resolvedTest1, resolvedTest4);
Assert.AreNotSame(resolvedTest2, resolvedTest4);
Assert.AreNotSame(resolvedTest3, resolvedTest5);
}
} }
} }
Loading…
Cancel
Save