#12: add option to register and resolve open generic types

pull/43/head
Simon G 5 years ago
parent 0ee10c8ba9
commit af65b7fd46
  1. 2
      LightweightIocContainer/Interfaces/IIocContainer.cs
  2. 64
      LightweightIocContainer/IocContainer.cs
  3. 4
      LightweightIocContainer/LightweightIocContainer.xml

@ -29,7 +29,7 @@ namespace LightweightIocContainer.Interfaces
/// <returns>The created <see cref="IRegistration"/></returns> /// <returns>The created <see cref="IRegistration"/></returns>
IDefaultRegistration<TInterface, TImplementation> Register<TInterface, TImplementation>(Lifestyle lifestyle = Lifestyle.Transient) where TImplementation : TInterface; IDefaultRegistration<TInterface, TImplementation> Register<TInterface, TImplementation>(Lifestyle lifestyle = Lifestyle.Transient) where TImplementation : TInterface;
IOpenGenericRegistration Register(Type tInterface, Type tImplementation, IOpenGenericRegistration RegisterOpenGenerics(Type tInterface, Type tImplementation,
Lifestyle lifestyle = Lifestyle.Transient); Lifestyle lifestyle = Lifestyle.Transient);
/// <summary> /// <summary>

@ -68,8 +68,14 @@ namespace LightweightIocContainer
return registration; return registration;
} }
public IOpenGenericRegistration Register(Type tInterface, Type tImplementation, Lifestyle lifestyle = Lifestyle.Transient) public IOpenGenericRegistration RegisterOpenGenerics(Type tInterface, Type tImplementation, Lifestyle lifestyle = Lifestyle.Transient)
{ {
if (!tInterface.ContainsGenericParameters)
throw new InvalidRegistrationException("This function can only be used to register open generic types.");
if (lifestyle == Lifestyle.Multiton)
throw new InvalidRegistrationException("Can't register a multiton with open generic registration."); //TODO: Is there any need for a possibility to register multitons with open generics?
IOpenGenericRegistration registration = _registrationFactory.Register(tInterface, tImplementation, lifestyle); IOpenGenericRegistration registration = _registrationFactory.Register(tInterface, tImplementation, lifestyle);
Register(registration); Register(registration);
@ -268,7 +274,7 @@ namespace LightweightIocContainer
/// <exception cref="UnknownRegistrationException">The registration for the given <see cref="Type"/> has an unknown <see cref="Type"/></exception> /// <exception cref="UnknownRegistrationException">The registration for the given <see cref="Type"/> has an unknown <see cref="Type"/></exception>
private T ResolveInternal<T>(object[] arguments, List<Type> resolveStack = null) private T ResolveInternal<T>(object[] arguments, List<Type> resolveStack = null)
{ {
IRegistration registration = _registrations.FirstOrDefault(r => r.InterfaceType == typeof(T)); IRegistration registration = FindRegistration<T>();
if (registration == null) if (registration == null)
throw new TypeNotRegisteredException(typeof(T)); throw new TypeNotRegisteredException(typeof(T));
@ -285,11 +291,11 @@ namespace LightweightIocContainer
if (registration is IRegistrationBase<T> defaultRegistration) if (registration is IRegistrationBase<T> defaultRegistration)
{ {
if (defaultRegistration.Lifestyle == Lifestyle.Singleton) if (defaultRegistration.Lifestyle == Lifestyle.Singleton)
resolvedInstance = GetOrCreateSingletonInstance(defaultRegistration, arguments, resolveStack); resolvedInstance = GetOrCreateSingletonInstance<T>(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)
resolvedInstance = GetOrCreateMultitonInstance(multitonRegistration, arguments, resolveStack); resolvedInstance = GetOrCreateMultitonInstance(multitonRegistration, arguments, resolveStack);
else else
resolvedInstance = CreateInstance(defaultRegistration, arguments, resolveStack); resolvedInstance = CreateInstance<T>(defaultRegistration, arguments, resolveStack);
} }
else if (registration is ITypedFactoryRegistration<T> typedFactoryRegistration) else if (registration is ITypedFactoryRegistration<T> typedFactoryRegistration)
{ {
@ -297,7 +303,10 @@ namespace LightweightIocContainer
} }
else if (registration is IOpenGenericRegistration openGenericRegistration) else if (registration is IOpenGenericRegistration openGenericRegistration)
{ {
if (openGenericRegistration.Lifestyle == Lifestyle.Singleton)
resolvedInstance = GetOrCreateSingletonInstance<T>(openGenericRegistration, arguments, resolveStack);
else
resolvedInstance = CreateInstance<T>(openGenericRegistration, arguments, resolveStack);
} }
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}.");
@ -315,13 +324,15 @@ namespace LightweightIocContainer
/// <param name="arguments">The arguments to resolve</param> /// <param name="arguments">The arguments to resolve</param>
/// <param name="resolveStack">The current resolve stack</param> /// <param name="resolveStack">The current resolve stack</param>
/// <returns>An existing or newly created singleton instance of the given <see cref="Type"/></returns> /// <returns>An existing or newly created singleton instance of the given <see cref="Type"/></returns>
private T GetOrCreateSingletonInstance<T>(IRegistrationBase<T> registration, object[] arguments, List<Type> resolveStack) private T GetOrCreateSingletonInstance<T>(IRegistration registration, object[] arguments, List<Type> resolveStack)
{ {
Type type; Type type;
if (registration is ITypedRegistrationBase<T> typedRegistration) if (registration is ITypedRegistrationBase<T> typedRegistration)
type = typedRegistration.ImplementationType; type = typedRegistration.ImplementationType;
else if (registration is ISingleTypeRegistration<T> singleTypeRegistration) else if (registration is ISingleTypeRegistration<T> singleTypeRegistration)
type = singleTypeRegistration.InterfaceType; type = singleTypeRegistration.InterfaceType;
else if (registration is IOpenGenericRegistration openGenericRegistration)
type = openGenericRegistration.ImplementationType;
else else
throw new UnknownRegistrationException($"There is no registration {registration.GetType().Name} that can have lifestyle singleton."); throw new UnknownRegistrationException($"There is no registration {registration.GetType().Name} that can have lifestyle singleton.");
@ -331,7 +342,7 @@ namespace LightweightIocContainer
return (T) instance; return (T) instance;
//if it doesn't already exist create a new instance and add it to the list //if it doesn't already exist create a new instance and add it to the list
T newInstance = CreateInstance(registration, arguments, resolveStack); T newInstance = CreateInstance<T>(registration, arguments, resolveStack);
_singletons.Add((type, newInstance)); _singletons.Add((type, newInstance));
return newInstance; return newInstance;
@ -363,13 +374,13 @@ namespace LightweightIocContainer
if (instances.TryGetValue(scopeArgument, out object instance)) if (instances.TryGetValue(scopeArgument, out object instance))
return (T) instance; return (T) instance;
T createdInstance = CreateInstance(registration, arguments, resolveStack); T createdInstance = CreateInstance<T>(registration, arguments, resolveStack);
instances.Add(scopeArgument, createdInstance); instances.Add(scopeArgument, createdInstance);
return createdInstance; return createdInstance;
} }
T newInstance = CreateInstance(registration, arguments, resolveStack); T newInstance = CreateInstance<T>(registration, arguments, resolveStack);
ConditionalWeakTable<object, object> weakTable = new ConditionalWeakTable<object, object>(); ConditionalWeakTable<object, object> weakTable = new ConditionalWeakTable<object, object>();
weakTable.Add(scopeArgument, newInstance); weakTable.Add(scopeArgument, newInstance);
@ -387,10 +398,10 @@ namespace LightweightIocContainer
/// <param name="arguments">The constructor arguments</param> /// <param name="arguments">The constructor arguments</param>
/// <param name="resolveStack">The current resolve stack</param> /// <param name="resolveStack">The current resolve stack</param>
/// <returns>A newly created instance of the given <see cref="Type"/></returns> /// <returns>A newly created instance of the given <see cref="Type"/></returns>
private T CreateInstance<T>(IRegistrationBase<T> registration, object[] arguments, List<Type> resolveStack) private T CreateInstance<T>(IRegistration registration, object[] arguments, List<Type> resolveStack)
{ {
if (registration.Parameters != null) if (registration is IWithParameters<T> registrationWithParameters && registrationWithParameters.Parameters != null)
arguments = UpdateArgumentsWithRegistrationParameters(registration, arguments); arguments = UpdateArgumentsWithRegistrationParameters(registrationWithParameters, arguments);
T instance; T instance;
if (registration is ITypedRegistrationBase<T> defaultRegistration) if (registration is ITypedRegistrationBase<T> defaultRegistration)
@ -411,6 +422,15 @@ namespace LightweightIocContainer
else //factory method set to create the instance else //factory method set to create the instance
instance = singleTypeRegistration.FactoryMethod(this); instance = singleTypeRegistration.FactoryMethod(this);
} }
else if (registration is IOpenGenericRegistration openGenericRegistration)
{
arguments = ResolveConstructorArguments(openGenericRegistration.ImplementationType, arguments, resolveStack);
//create generic implementation type from generic arguments of T
Type genericImplementationType = openGenericRegistration.ImplementationType.MakeGenericType(typeof(T).GenericTypeArguments);
instance = (T) Activator.CreateInstance(genericImplementationType, arguments);
}
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}.");
@ -550,6 +570,24 @@ namespace LightweightIocContainer
return null; return null;
} }
[CanBeNull]
private IRegistration FindRegistration<T>()
{
IRegistration registration = _registrations.FirstOrDefault(r => r.InterfaceType == typeof(T));
if (registration != null)
return registration;
//check for open generic registration
if (!typeof(T).GenericTypeArguments.Any())
return null;
List<IRegistration> openGenericRegistrations = _registrations.Where(r => r.InterfaceType.ContainsGenericParameters).ToList();
if (!openGenericRegistrations.Any())
return null;
return openGenericRegistrations.FirstOrDefault(r => r.InterfaceType == typeof(T).GetGenericTypeDefinition());
}
/// <summary> /// <summary>
/// Clear the multiton instances of the given <see cref="Type"/> from the registered multitons list /// Clear the multiton instances of the given <see cref="Type"/> from the registered multitons list
/// </summary> /// </summary>
@ -570,7 +608,7 @@ namespace LightweightIocContainer
/// </summary> /// </summary>
/// <typeparam name="T">The given <see cref="Type"/></typeparam> /// <typeparam name="T">The given <see cref="Type"/></typeparam>
/// <returns>True if the given <see cref="Type"/> is registered with this <see cref="IocContainer"/>, false if not</returns> /// <returns>True if the given <see cref="Type"/> is registered with this <see cref="IocContainer"/>, false if not</returns>
public bool IsTypeRegistered<T>() => _registrations.Any(registration => registration.InterfaceType == typeof(T)); public bool IsTypeRegistered<T>() => _registrations.Any(registration => registration.InterfaceType == typeof(T)); //TODO: Use FindRegistration<>()?
/// <summary> /// <summary>
/// The <see cref="IDisposable.Dispose"/> method /// The <see cref="IDisposable.Dispose"/> method

@ -826,7 +826,7 @@
<exception cref="T:LightweightIocContainer.Exceptions.TypeNotRegisteredException">The given <see cref="T:System.Type"/> is not registered in this <see cref="T:LightweightIocContainer.IocContainer"/></exception> <exception cref="T:LightweightIocContainer.Exceptions.TypeNotRegisteredException">The given <see cref="T:System.Type"/> is not registered in this <see cref="T:LightweightIocContainer.IocContainer"/></exception>
<exception cref="T:LightweightIocContainer.Exceptions.UnknownRegistrationException">The registration for the given <see cref="T:System.Type"/> has an unknown <see cref="T:System.Type"/></exception> <exception cref="T:LightweightIocContainer.Exceptions.UnknownRegistrationException">The registration for the given <see cref="T:System.Type"/> has an unknown <see cref="T:System.Type"/></exception>
</member> </member>
<member name="M:LightweightIocContainer.IocContainer.GetOrCreateSingletonInstance``1(LightweightIocContainer.Interfaces.Registrations.IRegistrationBase{``0},System.Object[],System.Collections.Generic.List{System.Type})"> <member name="M:LightweightIocContainer.IocContainer.GetOrCreateSingletonInstance``1(LightweightIocContainer.Interfaces.Registrations.IRegistration,System.Object[],System.Collections.Generic.List{System.Type})">
<summary> <summary>
Gets or creates a singleton instance of a given <see cref="T:System.Type"/> Gets or creates a singleton instance of a given <see cref="T:System.Type"/>
</summary> </summary>
@ -848,7 +848,7 @@
<exception cref="T:LightweightIocContainer.Exceptions.MultitonResolveException">No arguments given</exception> <exception cref="T:LightweightIocContainer.Exceptions.MultitonResolveException">No arguments given</exception>
<exception cref="T:LightweightIocContainer.Exceptions.MultitonResolveException">Scope argument not given</exception> <exception cref="T:LightweightIocContainer.Exceptions.MultitonResolveException">Scope argument not given</exception>
</member> </member>
<member name="M:LightweightIocContainer.IocContainer.CreateInstance``1(LightweightIocContainer.Interfaces.Registrations.IRegistrationBase{``0},System.Object[],System.Collections.Generic.List{System.Type})"> <member name="M:LightweightIocContainer.IocContainer.CreateInstance``1(LightweightIocContainer.Interfaces.Registrations.IRegistration,System.Object[],System.Collections.Generic.List{System.Type})">
<summary> <summary>
Creates an instance of a given <see cref="T:System.Type"/> Creates an instance of a given <see cref="T:System.Type"/>
</summary> </summary>

Loading…
Cancel
Save