Merge pull request #43 from SimonG96/OpenGenericRegistration

Open generic registration #12
pull/53/head
Simon G 5 years ago committed by GitHub
commit 89d42ea3d4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 24
      LightweightIocContainer/Exceptions/GenericMethodNotFoundException.cs
  2. 45
      LightweightIocContainer/GenericMethodCaller.cs
  3. 9
      LightweightIocContainer/Interfaces/IIocContainer.cs
  4. 19
      LightweightIocContainer/Interfaces/Registrations/IOpenGenericRegistration.cs
  5. 96
      LightweightIocContainer/IocContainer.cs
  6. 96
      LightweightIocContainer/LightweightIocContainer.xml
  7. 4
      LightweightIocContainer/Properties/AssemblyInfo.cs
  8. 50
      LightweightIocContainer/Registrations/OpenGenericRegistration.cs
  9. 5
      LightweightIocContainer/Registrations/RegistrationFactory.cs
  10. 3
      Test.LightweightIocContainer/EnumerableExtensionTest.cs
  11. 1
      Test.LightweightIocContainer/IocContainerRecursionTest.cs
  12. 70
      Test.LightweightIocContainer/OpenGenericRegistrationTest.cs

@ -0,0 +1,24 @@
// Author: Simon Gockner
// Created: 2020-09-18
// Copyright(c) 2020 SimonG. All Rights Reserved.
using System;
namespace LightweightIocContainer.Exceptions
{
/// <summary>
/// Could not find generic method
/// </summary>
public class GenericMethodNotFoundException : Exception
{
/// <summary>
/// Could not find generic method
/// </summary>
/// <param name="functionName">The name of the generic method</param>
public GenericMethodNotFoundException(string functionName)
: base($"Could not find function {functionName}")
{
}
}
}

@ -0,0 +1,45 @@
// Author: Simon Gockner
// Created: 2020-09-18
// Copyright(c) 2020 SimonG. All Rights Reserved.
using System;
using System.Reflection;
using LightweightIocContainer.Exceptions;
namespace LightweightIocContainer
{
/// <summary>
/// Helper class to call a generic method without generic type parameters
/// </summary>
internal static class GenericMethodCaller
{
/// <summary>
/// Call a generic method without generic type parameters
/// </summary>
/// <param name="caller">The caller of the method</param>
/// <param name="functionName">The name of the method to call</param>
/// <param name="genericParameter">The generic parameter as <see cref="Type"/> parameter</param>
/// <param name="bindingFlags">The <see cref="BindingFlags"/> to find the method</param>
/// <param name="parameters">The parameters of the method</param>
/// <returns>The result of invoking the method</returns>
/// <exception cref="GenericMethodNotFoundException">Could not find the generic method</exception>
/// <exception cref="Exception">Any <see cref="Exception"/> thrown after invoking the generic method</exception>
public static object Call(object caller, string functionName, Type genericParameter, BindingFlags bindingFlags, params object[] parameters)
{
MethodInfo method = caller.GetType().GetMethod(functionName, bindingFlags);
MethodInfo genericMethod = method?.MakeGenericMethod(genericParameter);
if (genericMethod == null)
throw new GenericMethodNotFoundException(functionName);
try //exceptions thrown by methods called with invoke are wrapped into another exception, the exception thrown by the invoked method can be returned by `Exception.GetBaseException()`
{
return genericMethod.Invoke(caller, parameters);
}
catch (Exception ex)
{
throw ex.GetBaseException();
}
}
}
}

@ -29,6 +29,15 @@ namespace LightweightIocContainer.Interfaces
/// <returns>The created <see cref="IRegistration"/></returns>
IDefaultRegistration<TInterface, TImplementation> Register<TInterface, TImplementation>(Lifestyle lifestyle = Lifestyle.Transient) where TImplementation : TInterface;
/// <summary>
/// Register an open generic Interface with an open generic Type that implements it
/// </summary>
/// <param name="tInterface">The open generic Interface to register</param>
/// <param name="tImplementation">The open generic Type that implements the interface</param>
/// <param name="lifestyle">The <see cref="Lifestyle"/> for this <see cref="IOpenGenericRegistration"/></param>
/// <returns>The created <see cref="IRegistration"/></returns>
IOpenGenericRegistration RegisterOpenGenerics(Type tInterface, Type tImplementation, Lifestyle lifestyle = Lifestyle.Transient);
/// <summary>
/// Register multiple interfaces for a <see cref="Type"/> that implements them
/// </summary>

@ -0,0 +1,19 @@
// Author: Simon Gockner
// Created: 2020-09-18
// Copyright(c) 2020 SimonG. All Rights Reserved.
using System;
namespace LightweightIocContainer.Interfaces.Registrations
{
/// <summary>
/// <see cref="IRegistration"/> for open generic types
/// </summary>
public interface IOpenGenericRegistration : IRegistration, ILifestyleProvider
{
/// <summary>
/// The <see cref="Type"/> that implements the <see cref="IRegistration.InterfaceType"/> that is registered with this <see cref="IOpenGenericRegistration"/>
/// </summary>
Type ImplementationType { get; }
}
}

@ -68,6 +68,29 @@ namespace LightweightIocContainer
return registration;
}
/// <summary>
/// Register an open generic Interface with an open generic Type that implements it
/// </summary>
/// <param name="tInterface">The open generic Interface to register</param>
/// <param name="tImplementation">The open generic Type that implements the interface</param>
/// <param name="lifestyle">The <see cref="Lifestyle"/> for this <see cref="IOpenGenericRegistration"/></param>
/// <returns>The created <see cref="IRegistration"/></returns>
/// <exception cref="InvalidRegistrationException">Function can only be used to register open generic types</exception>
/// <exception cref="InvalidRegistrationException">Can't register a multiton with open generic registration</exception>
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);
Register(registration);
return registration;
}
/// <summary>
/// Register multiple interfaces for a <see cref="Type"/> that implements them
/// </summary>
@ -246,20 +269,7 @@ namespace LightweightIocContainer
/// <exception cref="InternalResolveException">Could not find function <see cref="ResolveInternal{T}"/></exception>
private object Resolve(Type type, object[] arguments, List<Type> resolveStack)
{
MethodInfo resolveMethod = typeof(IocContainer).GetMethod(nameof(ResolveInternal), BindingFlags.NonPublic | BindingFlags.Instance);
MethodInfo genericResolveMethod = resolveMethod?.MakeGenericMethod(type);
if (genericResolveMethod == null)
throw new InternalResolveException($"Could not find function {nameof(ResolveInternal)}");
try //exceptions thrown by methods called with invoke are wrapped into another exception, the exception thrown by the invoked method can be returned by `Exception.GetBaseException()`
{
return genericResolveMethod.Invoke(this, new object[] { arguments, resolveStack });
}
catch (Exception ex)
{
throw ex.GetBaseException();
}
return GenericMethodCaller.Call(this, nameof(ResolveInternal), type, BindingFlags.NonPublic | BindingFlags.Instance, arguments, resolveStack);
}
/// <summary>
@ -273,7 +283,7 @@ namespace LightweightIocContainer
/// <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)
{
IRegistration registration = _registrations.FirstOrDefault(r => r.InterfaceType == typeof(T));
IRegistration registration = FindRegistration<T>();
if (registration == null)
throw new TypeNotRegisteredException(typeof(T));
@ -290,16 +300,23 @@ namespace LightweightIocContainer
if (registration is IRegistrationBase<T> defaultRegistration)
{
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)
resolvedInstance = GetOrCreateMultitonInstance(multitonRegistration, arguments, resolveStack);
else
resolvedInstance = CreateInstance(defaultRegistration, arguments, resolveStack);
resolvedInstance = CreateInstance<T>(defaultRegistration, arguments, resolveStack);
}
else if (registration is ITypedFactoryRegistration<T> typedFactoryRegistration)
{
resolvedInstance = typedFactoryRegistration.Factory.Factory;
}
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
throw new UnknownRegistrationException($"There is no registration of type {registration.GetType().Name}.");
@ -316,13 +333,15 @@ namespace LightweightIocContainer
/// <param name="arguments">The arguments to resolve</param>
/// <param name="resolveStack">The current resolve stack</param>
/// <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;
if (registration is ITypedRegistrationBase<T> typedRegistration)
type = typedRegistration.ImplementationType;
else if (registration is ISingleTypeRegistration<T> singleTypeRegistration)
type = singleTypeRegistration.InterfaceType;
else if (registration is IOpenGenericRegistration openGenericRegistration)
type = openGenericRegistration.ImplementationType;
else
throw new UnknownRegistrationException($"There is no registration {registration.GetType().Name} that can have lifestyle singleton.");
@ -332,7 +351,7 @@ namespace LightweightIocContainer
return (T) instance;
//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));
return newInstance;
@ -364,13 +383,13 @@ namespace LightweightIocContainer
if (instances.TryGetValue(scopeArgument, out object instance))
return (T) instance;
T createdInstance = CreateInstance(registration, arguments, resolveStack);
T createdInstance = CreateInstance<T>(registration, arguments, resolveStack);
instances.Add(scopeArgument, createdInstance);
return createdInstance;
}
T newInstance = CreateInstance(registration, arguments, resolveStack);
T newInstance = CreateInstance<T>(registration, arguments, resolveStack);
ConditionalWeakTable<object, object> weakTable = new ConditionalWeakTable<object, object>();
weakTable.Add(scopeArgument, newInstance);
@ -388,10 +407,10 @@ namespace LightweightIocContainer
/// <param name="arguments">The constructor arguments</param>
/// <param name="resolveStack">The current resolve stack</param>
/// <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)
arguments = UpdateArgumentsWithRegistrationParameters(registration, arguments);
if (registration is IWithParameters<T> registrationWithParameters && registrationWithParameters.Parameters != null)
arguments = UpdateArgumentsWithRegistrationParameters(registrationWithParameters, arguments);
T instance;
if (registration is ITypedRegistrationBase<T> defaultRegistration)
@ -412,6 +431,15 @@ namespace LightweightIocContainer
else //factory method set to create the instance
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
throw new UnknownRegistrationException($"There is no registration of type {registration.GetType().Name}.");
@ -551,6 +579,24 @@ namespace LightweightIocContainer
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>
/// Clear the multiton instances of the given <see cref="Type"/> from the registered multitons list
/// </summary>
@ -571,7 +617,7 @@ namespace LightweightIocContainer
/// </summary>
/// <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>
public bool IsTypeRegistered<T>() => _registrations.Any(registration => registration.InterfaceType == typeof(T));
public bool IsTypeRegistered<T>() => FindRegistration<T>() != null;
/// <summary>
/// The <see cref="IDisposable.Dispose"/> method

@ -86,6 +86,17 @@
The constructor that does not match
</summary>
</member>
<member name="T:LightweightIocContainer.Exceptions.GenericMethodNotFoundException">
<summary>
Could not find generic method
</summary>
</member>
<member name="M:LightweightIocContainer.Exceptions.GenericMethodNotFoundException.#ctor(System.String)">
<summary>
Could not find generic method
</summary>
<param name="functionName">The name of the generic method</param>
</member>
<member name="T:LightweightIocContainer.Exceptions.IllegalAbstractMethodCreationException">
<summary>
The creation of the abstract method is illegal in its current state
@ -274,6 +285,24 @@
The implemented abstract typed factory/>
</summary>
</member>
<member name="T:LightweightIocContainer.GenericMethodCaller">
<summary>
Helper class to call a generic method without generic type parameters
</summary>
</member>
<member name="M:LightweightIocContainer.GenericMethodCaller.Call(System.Object,System.String,System.Type,System.Reflection.BindingFlags,System.Object[])">
<summary>
Call a generic method without generic type parameters
</summary>
<param name="caller">The caller of the method</param>
<param name="functionName">The name of the method to call</param>
<param name="genericParameter">The generic parameter as <see cref="T:System.Type"/> parameter</param>
<param name="bindingFlags">The <see cref="T:System.Reflection.BindingFlags"/> to find the method</param>
<param name="parameters">The parameters of the method</param>
<returns>The result of invoking the method</returns>
<exception cref="T:LightweightIocContainer.Exceptions.GenericMethodNotFoundException">Could not find the generic method</exception>
<exception cref="T:System.Exception">Any <see cref="T:System.Exception"/> thrown after invoking the generic method</exception>
</member>
<member name="T:LightweightIocContainer.Installers.AssemblyInstaller">
<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"/>
@ -346,6 +375,15 @@
<param name="lifestyle">The <see cref="T:LightweightIocContainer.Lifestyle"/> for this <see cref="T:LightweightIocContainer.Interfaces.Registrations.IRegistrationBase`1"/></param>
<returns>The created <see cref="T:LightweightIocContainer.Interfaces.Registrations.IRegistration"/></returns>
</member>
<member name="M:LightweightIocContainer.Interfaces.IIocContainer.RegisterOpenGenerics(System.Type,System.Type,LightweightIocContainer.Lifestyle)">
<summary>
Register an open generic Interface with an open generic Type that implements it
</summary>
<param name="tInterface">The open generic Interface to register</param>
<param name="tImplementation">The open generic Type that implements the interface</param>
<param name="lifestyle">The <see cref="T:LightweightIocContainer.Lifestyle"/> for this <see cref="T:LightweightIocContainer.Interfaces.Registrations.IOpenGenericRegistration"/></param>
<returns>The created <see cref="T:LightweightIocContainer.Interfaces.Registrations.IRegistration"/></returns>
</member>
<member name="M:LightweightIocContainer.Interfaces.IIocContainer.Register``3(LightweightIocContainer.Lifestyle)">
<summary>
Register multiple interfaces for a <see cref="T:System.Type"/> that implements them
@ -609,6 +647,16 @@
<typeparam name="TInterface">The registered interface</typeparam>
<typeparam name="TImplementation">The registered implementation</typeparam>
</member>
<member name="T:LightweightIocContainer.Interfaces.Registrations.IOpenGenericRegistration">
<summary>
<see cref="T:LightweightIocContainer.Interfaces.Registrations.IRegistration"/> for open generic types
</summary>
</member>
<member name="P:LightweightIocContainer.Interfaces.Registrations.IOpenGenericRegistration.ImplementationType">
<summary>
The <see cref="T:System.Type"/> that implements the <see cref="P:LightweightIocContainer.Interfaces.Registrations.IRegistration.InterfaceType"/> that is registered with this <see cref="T:LightweightIocContainer.Interfaces.Registrations.IOpenGenericRegistration"/>
</summary>
</member>
<member name="T:LightweightIocContainer.Interfaces.Registrations.IRegistration">
<summary>
The base registration that is used to register an Interface
@ -705,6 +753,17 @@
<param name="lifestyle">The <see cref="T:LightweightIocContainer.Lifestyle"/> for this <see cref="T:LightweightIocContainer.Interfaces.Registrations.IRegistrationBase`1"/></param>
<returns>The created <see cref="T:LightweightIocContainer.Interfaces.Registrations.IRegistration"/></returns>
</member>
<member name="M:LightweightIocContainer.IocContainer.RegisterOpenGenerics(System.Type,System.Type,LightweightIocContainer.Lifestyle)">
<summary>
Register an open generic Interface with an open generic Type that implements it
</summary>
<param name="tInterface">The open generic Interface to register</param>
<param name="tImplementation">The open generic Type that implements the interface</param>
<param name="lifestyle">The <see cref="T:LightweightIocContainer.Lifestyle"/> for this <see cref="T:LightweightIocContainer.Interfaces.Registrations.IOpenGenericRegistration"/></param>
<returns>The created <see cref="T:LightweightIocContainer.Interfaces.Registrations.IRegistration"/></returns>
<exception cref="T:LightweightIocContainer.Exceptions.InvalidRegistrationException">Function can only be used to register open generic types</exception>
<exception cref="T:LightweightIocContainer.Exceptions.InvalidRegistrationException">Can't register a multiton with open generic registration</exception>
</member>
<member name="M:LightweightIocContainer.IocContainer.Register``3(LightweightIocContainer.Lifestyle)">
<summary>
Register multiple interfaces for a <see cref="T:System.Type"/> that implements them
@ -826,7 +885,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.UnknownRegistrationException">The registration for the given <see cref="T:System.Type"/> has an unknown <see cref="T:System.Type"/></exception>
</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>
Gets or creates a singleton instance of a given <see cref="T:System.Type"/>
</summary>
@ -848,7 +907,7 @@
<exception cref="T:LightweightIocContainer.Exceptions.MultitonResolveException">No arguments given</exception>
<exception cref="T:LightweightIocContainer.Exceptions.MultitonResolveException">Scope argument not given</exception>
</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>
Creates an instance of a given <see cref="T:System.Type"/>
</summary>
@ -1078,6 +1137,39 @@
The <see cref="T:System.Type"/> of the multiton scope
</summary>
</member>
<member name="T:LightweightIocContainer.Registrations.OpenGenericRegistration">
<summary>
<see cref="T:LightweightIocContainer.Interfaces.Registrations.IRegistration"/> for open generic types
</summary>
</member>
<member name="M:LightweightIocContainer.Registrations.OpenGenericRegistration.#ctor(System.Type,System.Type,LightweightIocContainer.Lifestyle)">
<summary>
<see cref="T:LightweightIocContainer.Interfaces.Registrations.IRegistration"/> for open generic types
</summary>
<param name="interfaceType">The <see cref="T:System.Type"/> of the interface</param>
<param name="implementationType">The <see cref="T:System.Type"/> of the implementation type</param>
<param name="lifestyle">The <see cref="P:LightweightIocContainer.Registrations.OpenGenericRegistration.Lifestyle"/> of this <see cref="T:LightweightIocContainer.Interfaces.Registrations.IOpenGenericRegistration"/></param>
</member>
<member name="P:LightweightIocContainer.Registrations.OpenGenericRegistration.Name">
<summary>
The name of the <see cref="T:LightweightIocContainer.Interfaces.Registrations.IRegistration"/>
</summary>
</member>
<member name="P:LightweightIocContainer.Registrations.OpenGenericRegistration.InterfaceType">
<summary>
The <see cref="T:System.Type"/> of the Interface that is registered with this <see cref="T:LightweightIocContainer.Interfaces.Registrations.IRegistration"/>
</summary>
</member>
<member name="P:LightweightIocContainer.Registrations.OpenGenericRegistration.ImplementationType">
<summary>
The <see cref="T:System.Type"/> that implements the <see cref="P:LightweightIocContainer.Interfaces.Registrations.IRegistration.InterfaceType"/> that is registered with this <see cref="T:LightweightIocContainer.Interfaces.Registrations.IOpenGenericRegistration"/>
</summary>
</member>
<member name="P:LightweightIocContainer.Registrations.OpenGenericRegistration.Lifestyle">
<summary>
The Lifestyle of Instances that are created with this <see cref="T:LightweightIocContainer.Interfaces.Registrations.IRegistration"/>
</summary>
</member>
<member name="T:LightweightIocContainer.Registrations.RegistrationBase`1">
<summary>
The <see cref="T:LightweightIocContainer.Registrations.RegistrationBase`1"/> that is used to register an Interface

@ -5,7 +5,3 @@
using System.Runtime.CompilerServices;
[assembly:InternalsVisibleTo("Test.LightweightIocContainer")]
namespace LightweightIocContainer.Properties
{
}

@ -0,0 +1,50 @@
// Author: Simon Gockner
// Created: 2020-09-18
// Copyright(c) 2020 SimonG. All Rights Reserved.
using System;
using LightweightIocContainer.Interfaces.Registrations;
namespace LightweightIocContainer.Registrations
{
/// <summary>
/// <see cref="IRegistration"/> for open generic types
/// </summary>
public class OpenGenericRegistration : IOpenGenericRegistration
{
/// <summary>
/// <see cref="IRegistration"/> for open generic types
/// </summary>
/// <param name="interfaceType">The <see cref="Type"/> of the interface</param>
/// <param name="implementationType">The <see cref="Type"/> of the implementation type</param>
/// <param name="lifestyle">The <see cref="Lifestyle"/> of this <see cref="IOpenGenericRegistration"/></param>
public OpenGenericRegistration(Type interfaceType, Type implementationType, Lifestyle lifestyle)
{
InterfaceType = interfaceType;
ImplementationType = implementationType;
Lifestyle = lifestyle;
Name = $"{InterfaceType.Name}, {ImplementationType.Name}, Lifestyle: {Lifestyle.ToString()}";
}
/// <summary>
/// The name of the <see cref="IRegistration"/>
/// </summary>
public string Name { get; }
/// <summary>
/// The <see cref="Type"/> of the Interface that is registered with this <see cref="IRegistration"/>
/// </summary>
public Type InterfaceType { get; }
/// <summary>
/// The <see cref="Type"/> that implements the <see cref="IRegistration.InterfaceType"/> that is registered with this <see cref="IOpenGenericRegistration"/>
/// </summary>
public Type ImplementationType { get; }
/// <summary>
/// The Lifestyle of Instances that are created with this <see cref="IRegistration"/>
/// </summary>
public Lifestyle Lifestyle { get; }
}
}

@ -33,6 +33,11 @@ namespace LightweightIocContainer.Registrations
return new DefaultRegistration<TInterface, TImplementation>(typeof(TInterface), typeof(TImplementation), lifestyle);
}
public IOpenGenericRegistration Register(Type tInterface, Type tImplementation, Lifestyle lifestyle)
{
return new OpenGenericRegistration(tInterface, tImplementation, lifestyle);
}
/// <summary>
/// Register multiple interfaces for a <see cref="Type"/> that implements them and create a <see cref="IMultipleRegistration{TInterface1,TInterface2}"/>
/// </summary>

@ -3,6 +3,7 @@
// Copyright(c) 2019 SimonG. All Rights Reserved.
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using LightweightIocContainer;
using NUnit.Framework;
@ -27,6 +28,7 @@ namespace Test.LightweightIocContainer
[Test]
[SuppressMessage("ReSharper", "CollectionNeverUpdated.Local")]
public void TestFirstOrGivenNoPredicateEmpty()
{
List<ListObject> list = new List<ListObject>();
@ -51,6 +53,7 @@ namespace Test.LightweightIocContainer
}
[Test]
[SuppressMessage("ReSharper", "CollectionNeverUpdated.Local")]
public void TestFirstOrGivenPredicateEmpty()
{
List<ListObject> list = new List<ListObject>();

@ -141,6 +141,7 @@ namespace Test.LightweightIocContainer
_iocContainer.Register<IC, C>();
IA a = _iocContainer.Resolve<IA>();
Assert.IsNotNull(a);
}
[Test]

@ -0,0 +1,70 @@
// Author: Simon Gockner
// Created: 2020-09-18
// Copyright(c) 2020 SimonG. All Rights Reserved.
using System.Diagnostics.CodeAnalysis;
using JetBrains.Annotations;
using LightweightIocContainer;
using LightweightIocContainer.Exceptions;
using LightweightIocContainer.Interfaces;
using NUnit.Framework;
namespace Test.LightweightIocContainer
{
[TestFixture]
public class OpenGenericRegistrationTest
{
private IIocContainer _iocContainer;
[UsedImplicitly]
[SuppressMessage("ReSharper", "UnusedTypeParameter")]
public interface ITest<T>
{
}
[UsedImplicitly]
public class Test<T> : ITest<T>
{
}
[SetUp]
public void SetUp() => _iocContainer = new IocContainer();
[TearDown]
public void TearDown() => _iocContainer.Dispose();
[Test]
public void TestRegisterOpenGenericType()
{
_iocContainer.RegisterOpenGenerics(typeof(ITest<>), typeof(Test<>));
ITest<int> test = _iocContainer.Resolve<ITest<int>>();
Assert.NotNull(test);
}
[Test]
public void TestRegisterOpenGenericTypeAsSingleton()
{
_iocContainer.RegisterOpenGenerics(typeof(ITest<>), typeof(Test<>), Lifestyle.Singleton);
ITest<int> test = _iocContainer.Resolve<ITest<int>>();
Assert.NotNull(test);
ITest<int> secondTest = _iocContainer.Resolve<ITest<int>>();
Assert.NotNull(secondTest);
Assert.AreEqual(test, secondTest);
Assert.AreSame(test, secondTest);
}
[Test]
public void TestRegisterOpenGenericTypeAsMultitonThrowsException()
=> Assert.Throws<InvalidRegistrationException>(() => _iocContainer.RegisterOpenGenerics(typeof(ITest<>), typeof(Test<>), Lifestyle.Multiton));
[Test]
public void TestRegisterNonOpenGenericTypeWithOpenGenericsFunctionThrowsException()
=> Assert.Throws<InvalidRegistrationException>(() => _iocContainer.RegisterOpenGenerics(typeof(int), typeof(int)));
}
}
Loading…
Cancel
Save