From 2225c28e001cb71bad55467c246332ebcefc87fc Mon Sep 17 00:00:00 2001 From: Simon G Date: Fri, 18 Sep 2020 22:37:17 +0200 Subject: [PATCH 1/8] - add GenericMethodCaller --- .../GenericMethodNotFoundException.cs | 17 ++++++++++ .../GenericMethodCaller.cs | 31 +++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 LightweightIocContainer/Exceptions/GenericMethodNotFoundException.cs create mode 100644 LightweightIocContainer/GenericMethodCaller.cs diff --git a/LightweightIocContainer/Exceptions/GenericMethodNotFoundException.cs b/LightweightIocContainer/Exceptions/GenericMethodNotFoundException.cs new file mode 100644 index 0000000..136eb24 --- /dev/null +++ b/LightweightIocContainer/Exceptions/GenericMethodNotFoundException.cs @@ -0,0 +1,17 @@ +// Author: Simon Gockner +// Created: 2020-09-18 +// Copyright(c) 2020 SimonG. All Rights Reserved. + +using System; + +namespace LightweightIocContainer.Exceptions +{ + public class GenericMethodNotFoundException : Exception + { + public GenericMethodNotFoundException(string functionName) + : base($"Could not find function {functionName}") + { + + } + } +} \ No newline at end of file diff --git a/LightweightIocContainer/GenericMethodCaller.cs b/LightweightIocContainer/GenericMethodCaller.cs new file mode 100644 index 0000000..799b4b7 --- /dev/null +++ b/LightweightIocContainer/GenericMethodCaller.cs @@ -0,0 +1,31 @@ +// Author: Simon Gockner +// Created: 2020-09-18 +// Copyright(c) 2020 SimonG. All Rights Reserved. + +using System; +using System.Reflection; +using LightweightIocContainer.Exceptions; + +namespace LightweightIocContainer +{ + public static class GenericMethodCaller + { + 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(); + } + } + } +} \ No newline at end of file From e816546eb2f201f31c3c4849169043df48d825c3 Mon Sep 17 00:00:00 2001 From: Simon G Date: Fri, 18 Sep 2020 22:37:35 +0200 Subject: [PATCH 2/8] - add OpenGenericRegistration --- .../Registrations/IOpenGenericRegistration.cs | 13 ++++++++++ .../Registrations/OpenGenericRegistration.cs | 26 +++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 LightweightIocContainer/Interfaces/Registrations/IOpenGenericRegistration.cs create mode 100644 LightweightIocContainer/Registrations/OpenGenericRegistration.cs diff --git a/LightweightIocContainer/Interfaces/Registrations/IOpenGenericRegistration.cs b/LightweightIocContainer/Interfaces/Registrations/IOpenGenericRegistration.cs new file mode 100644 index 0000000..4081365 --- /dev/null +++ b/LightweightIocContainer/Interfaces/Registrations/IOpenGenericRegistration.cs @@ -0,0 +1,13 @@ +// Author: Simon Gockner +// Created: 2020-09-18 +// Copyright(c) 2020 SimonG. All Rights Reserved. + +using System; + +namespace LightweightIocContainer.Interfaces.Registrations +{ + public interface IOpenGenericRegistration : IRegistration, ILifestyleProvider + { + Type ImplementationType { get; } + } +} \ No newline at end of file diff --git a/LightweightIocContainer/Registrations/OpenGenericRegistration.cs b/LightweightIocContainer/Registrations/OpenGenericRegistration.cs new file mode 100644 index 0000000..03a51f1 --- /dev/null +++ b/LightweightIocContainer/Registrations/OpenGenericRegistration.cs @@ -0,0 +1,26 @@ +// Author: Simon Gockner +// Created: 2020-09-18 +// Copyright(c) 2020 SimonG. All Rights Reserved. + +using System; +using LightweightIocContainer.Interfaces.Registrations; + +namespace LightweightIocContainer.Registrations +{ + public class OpenGenericRegistration : IOpenGenericRegistration + { + public OpenGenericRegistration(Type interfaceType, Type implementationType, Lifestyle lifestyle) + { + InterfaceType = interfaceType; + ImplementationType = implementationType; + Lifestyle = lifestyle; + + Name = $"{InterfaceType.Name}, {ImplementationType.Name}, Lifestyle: {Lifestyle.ToString()}"; + } + + public string Name { get; } + public Type InterfaceType { get; } + public Type ImplementationType { get; } + public Lifestyle Lifestyle { get; } + } +} \ No newline at end of file From 0b2879ddc3f2534cf5189ca2ffa4da3706ef79a3 Mon Sep 17 00:00:00 2001 From: Simon G Date: Fri, 18 Sep 2020 22:38:19 +0200 Subject: [PATCH 3/8] - add registration methods for OpenGenericRegistration --- .../Interfaces/IIocContainer.cs | 3 +++ LightweightIocContainer/IocContainer.cs | 27 +++++++++---------- .../Registrations/RegistrationFactory.cs | 5 ++++ 3 files changed, 21 insertions(+), 14 deletions(-) diff --git a/LightweightIocContainer/Interfaces/IIocContainer.cs b/LightweightIocContainer/Interfaces/IIocContainer.cs index 62a4434..fe0f94a 100644 --- a/LightweightIocContainer/Interfaces/IIocContainer.cs +++ b/LightweightIocContainer/Interfaces/IIocContainer.cs @@ -29,6 +29,9 @@ namespace LightweightIocContainer.Interfaces /// The created IDefaultRegistration Register(Lifestyle lifestyle = Lifestyle.Transient) where TImplementation : TInterface; + IOpenGenericRegistration Register(Type tInterface, Type tImplementation, + Lifestyle lifestyle = Lifestyle.Transient); + /// /// Register multiple interfaces for a that implements them /// diff --git a/LightweightIocContainer/IocContainer.cs b/LightweightIocContainer/IocContainer.cs index 6f114be..bf5f1a2 100644 --- a/LightweightIocContainer/IocContainer.cs +++ b/LightweightIocContainer/IocContainer.cs @@ -68,6 +68,14 @@ namespace LightweightIocContainer return registration; } + public IOpenGenericRegistration Register(Type tInterface, Type tImplementation, Lifestyle lifestyle = Lifestyle.Transient) + { + IOpenGenericRegistration registration = _registrationFactory.Register(tInterface, tImplementation, lifestyle); + Register(registration); + + return registration; + } + /// /// Register multiple interfaces for a that implements them /// @@ -246,20 +254,7 @@ namespace LightweightIocContainer /// Could not find function private object Resolve(Type type, object[] arguments, List 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); } /// @@ -299,6 +294,10 @@ namespace LightweightIocContainer else if (registration is ITypedFactoryRegistration typedFactoryRegistration) { resolvedInstance = typedFactoryRegistration.Factory.Factory; + } + else if (registration is IOpenGenericRegistration openGenericRegistration) + { + } else throw new UnknownRegistrationException($"There is no registration of type {registration.GetType().Name}."); diff --git a/LightweightIocContainer/Registrations/RegistrationFactory.cs b/LightweightIocContainer/Registrations/RegistrationFactory.cs index f87383c..7ff2487 100644 --- a/LightweightIocContainer/Registrations/RegistrationFactory.cs +++ b/LightweightIocContainer/Registrations/RegistrationFactory.cs @@ -33,6 +33,11 @@ namespace LightweightIocContainer.Registrations return new DefaultRegistration(typeof(TInterface), typeof(TImplementation), lifestyle); } + public IOpenGenericRegistration Register(Type tInterface, Type tImplementation, Lifestyle lifestyle) + { + return new OpenGenericRegistration(tInterface, tImplementation, lifestyle); + } + /// /// Register multiple interfaces for a that implements them and create a /// From 0ee10c8ba91407599ada9cd74e4f713f48bf8cff Mon Sep 17 00:00:00 2001 From: Simon G Date: Fri, 18 Sep 2020 22:38:31 +0200 Subject: [PATCH 4/8] - add OpenGenericRegistrationTest --- .../OpenGenericRegistrationTest.cs | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 Test.LightweightIocContainer/OpenGenericRegistrationTest.cs diff --git a/Test.LightweightIocContainer/OpenGenericRegistrationTest.cs b/Test.LightweightIocContainer/OpenGenericRegistrationTest.cs new file mode 100644 index 0000000..d5d5ff4 --- /dev/null +++ b/Test.LightweightIocContainer/OpenGenericRegistrationTest.cs @@ -0,0 +1,34 @@ +// Author: Simon Gockner +// Created: 2020-09-18 +// Copyright(c) 2020 SimonG. All Rights Reserved. + +using LightweightIocContainer; +using LightweightIocContainer.Interfaces; +using NUnit.Framework; + +namespace Test.LightweightIocContainer +{ + [TestFixture] + public class OpenGenericRegistrationTest + { + public interface ITest + { + + } + + public class Test : ITest + { + + } + + [Test] + public void TestRegisterOpenGenericType() + { + IIocContainer iocContainer = new IocContainer(); + iocContainer.Register(typeof(ITest<>), typeof(Test<>)); + + ITest test = iocContainer.Resolve>(); + Assert.NotNull(test); + } + } +} \ No newline at end of file From af65b7fd46b36ea2fe17adb6230748a8afb926e4 Mon Sep 17 00:00:00 2001 From: Simon G Date: Fri, 23 Oct 2020 14:54:13 +0200 Subject: [PATCH 5/8] #12: add option to register and resolve open generic types --- .../Interfaces/IIocContainer.cs | 2 +- LightweightIocContainer/IocContainer.cs | 64 +++++++++++++++---- .../LightweightIocContainer.xml | 4 +- 3 files changed, 54 insertions(+), 16 deletions(-) diff --git a/LightweightIocContainer/Interfaces/IIocContainer.cs b/LightweightIocContainer/Interfaces/IIocContainer.cs index fe0f94a..7718672 100644 --- a/LightweightIocContainer/Interfaces/IIocContainer.cs +++ b/LightweightIocContainer/Interfaces/IIocContainer.cs @@ -29,7 +29,7 @@ namespace LightweightIocContainer.Interfaces /// The created IDefaultRegistration Register(Lifestyle lifestyle = Lifestyle.Transient) where TImplementation : TInterface; - IOpenGenericRegistration Register(Type tInterface, Type tImplementation, + IOpenGenericRegistration RegisterOpenGenerics(Type tInterface, Type tImplementation, Lifestyle lifestyle = Lifestyle.Transient); /// diff --git a/LightweightIocContainer/IocContainer.cs b/LightweightIocContainer/IocContainer.cs index bf5f1a2..430d603 100644 --- a/LightweightIocContainer/IocContainer.cs +++ b/LightweightIocContainer/IocContainer.cs @@ -68,8 +68,14 @@ namespace LightweightIocContainer 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); Register(registration); @@ -268,7 +274,7 @@ namespace LightweightIocContainer /// The registration for the given has an unknown private T ResolveInternal(object[] arguments, List resolveStack = null) { - IRegistration registration = _registrations.FirstOrDefault(r => r.InterfaceType == typeof(T)); + IRegistration registration = FindRegistration(); if (registration == null) throw new TypeNotRegisteredException(typeof(T)); @@ -285,11 +291,11 @@ namespace LightweightIocContainer if (registration is IRegistrationBase defaultRegistration) { if (defaultRegistration.Lifestyle == Lifestyle.Singleton) - resolvedInstance = GetOrCreateSingletonInstance(defaultRegistration, arguments, resolveStack); + resolvedInstance = GetOrCreateSingletonInstance(defaultRegistration, arguments, resolveStack); else if (defaultRegistration is IMultitonRegistration multitonRegistration && defaultRegistration.Lifestyle == Lifestyle.Multiton) resolvedInstance = GetOrCreateMultitonInstance(multitonRegistration, arguments, resolveStack); else - resolvedInstance = CreateInstance(defaultRegistration, arguments, resolveStack); + resolvedInstance = CreateInstance(defaultRegistration, arguments, resolveStack); } else if (registration is ITypedFactoryRegistration typedFactoryRegistration) { @@ -297,7 +303,10 @@ namespace LightweightIocContainer } else if (registration is IOpenGenericRegistration openGenericRegistration) { - + if (openGenericRegistration.Lifestyle == Lifestyle.Singleton) + resolvedInstance = GetOrCreateSingletonInstance(openGenericRegistration, arguments, resolveStack); + else + resolvedInstance = CreateInstance(openGenericRegistration, arguments, resolveStack); } else throw new UnknownRegistrationException($"There is no registration of type {registration.GetType().Name}."); @@ -315,13 +324,15 @@ namespace LightweightIocContainer /// The arguments to resolve /// The current resolve stack /// An existing or newly created singleton instance of the given - private T GetOrCreateSingletonInstance(IRegistrationBase registration, object[] arguments, List resolveStack) + private T GetOrCreateSingletonInstance(IRegistration registration, object[] arguments, List resolveStack) { Type type; if (registration is ITypedRegistrationBase typedRegistration) type = typedRegistration.ImplementationType; else if (registration is ISingleTypeRegistration 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."); @@ -331,7 +342,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(registration, arguments, resolveStack); _singletons.Add((type, newInstance)); return newInstance; @@ -363,13 +374,13 @@ namespace LightweightIocContainer if (instances.TryGetValue(scopeArgument, out object instance)) return (T) instance; - T createdInstance = CreateInstance(registration, arguments, resolveStack); + T createdInstance = CreateInstance(registration, arguments, resolveStack); instances.Add(scopeArgument, createdInstance); return createdInstance; } - T newInstance = CreateInstance(registration, arguments, resolveStack); + T newInstance = CreateInstance(registration, arguments, resolveStack); ConditionalWeakTable weakTable = new ConditionalWeakTable(); weakTable.Add(scopeArgument, newInstance); @@ -387,10 +398,10 @@ namespace LightweightIocContainer /// The constructor arguments /// The current resolve stack /// A newly created instance of the given - private T CreateInstance(IRegistrationBase registration, object[] arguments, List resolveStack) + private T CreateInstance(IRegistration registration, object[] arguments, List resolveStack) { - if (registration.Parameters != null) - arguments = UpdateArgumentsWithRegistrationParameters(registration, arguments); + if (registration is IWithParameters registrationWithParameters && registrationWithParameters.Parameters != null) + arguments = UpdateArgumentsWithRegistrationParameters(registrationWithParameters, arguments); T instance; if (registration is ITypedRegistrationBase defaultRegistration) @@ -411,6 +422,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}."); @@ -550,6 +570,24 @@ namespace LightweightIocContainer return null; } + [CanBeNull] + private IRegistration FindRegistration() + { + 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 openGenericRegistrations = _registrations.Where(r => r.InterfaceType.ContainsGenericParameters).ToList(); + if (!openGenericRegistrations.Any()) + return null; + + return openGenericRegistrations.FirstOrDefault(r => r.InterfaceType == typeof(T).GetGenericTypeDefinition()); + } + /// /// Clear the multiton instances of the given from the registered multitons list /// @@ -570,7 +608,7 @@ namespace LightweightIocContainer /// /// The given /// True if the given is registered with this , false if not - public bool IsTypeRegistered() => _registrations.Any(registration => registration.InterfaceType == typeof(T)); + public bool IsTypeRegistered() => _registrations.Any(registration => registration.InterfaceType == typeof(T)); //TODO: Use FindRegistration<>()? /// /// The method diff --git a/LightweightIocContainer/LightweightIocContainer.xml b/LightweightIocContainer/LightweightIocContainer.xml index b25a486..331e407 100644 --- a/LightweightIocContainer/LightweightIocContainer.xml +++ b/LightweightIocContainer/LightweightIocContainer.xml @@ -826,7 +826,7 @@ The given is not registered in this The registration for the given has an unknown - + Gets or creates a singleton instance of a given @@ -848,7 +848,7 @@ No arguments given Scope argument not given - + Creates an instance of a given From f58e5f12545ce2f654cadcc386d13b4b4496f276 Mon Sep 17 00:00:00 2001 From: Simon G Date: Fri, 23 Oct 2020 14:54:22 +0200 Subject: [PATCH 6/8] #12: update test --- .../OpenGenericRegistrationTest.cs | 42 +++++++++++++++++-- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/Test.LightweightIocContainer/OpenGenericRegistrationTest.cs b/Test.LightweightIocContainer/OpenGenericRegistrationTest.cs index d5d5ff4..391a96a 100644 --- a/Test.LightweightIocContainer/OpenGenericRegistrationTest.cs +++ b/Test.LightweightIocContainer/OpenGenericRegistrationTest.cs @@ -2,7 +2,9 @@ // Created: 2020-09-18 // Copyright(c) 2020 SimonG. All Rights Reserved. +using JetBrains.Annotations; using LightweightIocContainer; +using LightweightIocContainer.Exceptions; using LightweightIocContainer.Interfaces; using NUnit.Framework; @@ -11,24 +13,56 @@ namespace Test.LightweightIocContainer [TestFixture] public class OpenGenericRegistrationTest { + private IIocContainer _iocContainer; + + [UsedImplicitly] public interface ITest { } + [UsedImplicitly] public class Test : ITest { } - + + [SetUp] + public void SetUp() => _iocContainer = new IocContainer(); + + [TearDown] + public void TearDown() => _iocContainer.Dispose(); + [Test] public void TestRegisterOpenGenericType() { - IIocContainer iocContainer = new IocContainer(); - iocContainer.Register(typeof(ITest<>), typeof(Test<>)); + _iocContainer.RegisterOpenGenerics(typeof(ITest<>), typeof(Test<>)); - ITest test = iocContainer.Resolve>(); + ITest test = _iocContainer.Resolve>(); Assert.NotNull(test); } + + [Test] + public void TestRegisterOpenGenericTypeAsSingleton() + { + _iocContainer.RegisterOpenGenerics(typeof(ITest<>), typeof(Test<>), Lifestyle.Singleton); + + ITest test = _iocContainer.Resolve>(); + Assert.NotNull(test); + + ITest secondTest = _iocContainer.Resolve>(); + Assert.NotNull(secondTest); + + Assert.AreEqual(test, secondTest); + Assert.AreSame(test, secondTest); + } + + [Test] + public void TestRegisterOpenGenericTypeAsMultitonThrowsException() + => Assert.Throws(() => _iocContainer.RegisterOpenGenerics(typeof(ITest<>), typeof(Test<>), Lifestyle.Multiton)); + + [Test] + public void TestRegisterNonOpenGenericTypeWithOpenGenericsFunctionThrowsException() + => Assert.Throws(() => _iocContainer.RegisterOpenGenerics(typeof(int), typeof(int))); } } \ No newline at end of file From 7a22bdaf1272ea29627851601b46c094d5832f5a Mon Sep 17 00:00:00 2001 From: Simon G Date: Fri, 23 Oct 2020 14:55:17 +0200 Subject: [PATCH 7/8] - use new FindRegistration<>() method for IsTypeRegistered<>() as well --- LightweightIocContainer/IocContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LightweightIocContainer/IocContainer.cs b/LightweightIocContainer/IocContainer.cs index 430d603..c93abe1 100644 --- a/LightweightIocContainer/IocContainer.cs +++ b/LightweightIocContainer/IocContainer.cs @@ -608,7 +608,7 @@ namespace LightweightIocContainer /// /// The given /// True if the given is registered with this , false if not - public bool IsTypeRegistered() => _registrations.Any(registration => registration.InterfaceType == typeof(T)); //TODO: Use FindRegistration<>()? + public bool IsTypeRegistered() => FindRegistration() != null; /// /// The method From 699a852506e99bf189ef18de625908a0e49bf6c8 Mon Sep 17 00:00:00 2001 From: Simon G Date: Fri, 23 Oct 2020 15:13:31 +0200 Subject: [PATCH 8/8] #12: fix warnings and add comments --- .../GenericMethodNotFoundException.cs | 7 ++ .../GenericMethodCaller.cs | 16 +++- .../Interfaces/IIocContainer.cs | 10 +- .../Registrations/IOpenGenericRegistration.cs | 6 ++ LightweightIocContainer/IocContainer.cs | 9 ++ .../LightweightIocContainer.xml | 92 +++++++++++++++++++ .../Properties/AssemblyInfo.cs | 6 +- .../Registrations/OpenGenericRegistration.cs | 24 +++++ .../EnumerableExtensionTest.cs | 3 + .../IocContainerRecursionTest.cs | 1 + .../OpenGenericRegistrationTest.cs | 2 + 11 files changed, 168 insertions(+), 8 deletions(-) diff --git a/LightweightIocContainer/Exceptions/GenericMethodNotFoundException.cs b/LightweightIocContainer/Exceptions/GenericMethodNotFoundException.cs index 136eb24..1438b54 100644 --- a/LightweightIocContainer/Exceptions/GenericMethodNotFoundException.cs +++ b/LightweightIocContainer/Exceptions/GenericMethodNotFoundException.cs @@ -6,8 +6,15 @@ using System; namespace LightweightIocContainer.Exceptions { + /// + /// Could not find generic method + /// public class GenericMethodNotFoundException : Exception { + /// + /// Could not find generic method + /// + /// The name of the generic method public GenericMethodNotFoundException(string functionName) : base($"Could not find function {functionName}") { diff --git a/LightweightIocContainer/GenericMethodCaller.cs b/LightweightIocContainer/GenericMethodCaller.cs index 799b4b7..bff301d 100644 --- a/LightweightIocContainer/GenericMethodCaller.cs +++ b/LightweightIocContainer/GenericMethodCaller.cs @@ -8,8 +8,22 @@ using LightweightIocContainer.Exceptions; namespace LightweightIocContainer { - public static class GenericMethodCaller + /// + /// Helper class to call a generic method without generic type parameters + /// + internal static class GenericMethodCaller { + /// + /// Call a generic method without generic type parameters + /// + /// The caller of the method + /// The name of the method to call + /// The generic parameter as parameter + /// The to find the method + /// The parameters of the method + /// The result of invoking the method + /// Could not find the generic method + /// Any thrown after invoking the generic method public static object Call(object caller, string functionName, Type genericParameter, BindingFlags bindingFlags, params object[] parameters) { MethodInfo method = caller.GetType().GetMethod(functionName, bindingFlags); diff --git a/LightweightIocContainer/Interfaces/IIocContainer.cs b/LightweightIocContainer/Interfaces/IIocContainer.cs index 7718672..d4c1465 100644 --- a/LightweightIocContainer/Interfaces/IIocContainer.cs +++ b/LightweightIocContainer/Interfaces/IIocContainer.cs @@ -29,8 +29,14 @@ namespace LightweightIocContainer.Interfaces /// The created IDefaultRegistration Register(Lifestyle lifestyle = Lifestyle.Transient) where TImplementation : TInterface; - IOpenGenericRegistration RegisterOpenGenerics(Type tInterface, Type tImplementation, - Lifestyle lifestyle = Lifestyle.Transient); + /// + /// Register an open generic Interface with an open generic Type that implements it + /// + /// The open generic Interface to register + /// The open generic Type that implements the interface + /// The for this + /// The created + IOpenGenericRegistration RegisterOpenGenerics(Type tInterface, Type tImplementation, Lifestyle lifestyle = Lifestyle.Transient); /// /// Register multiple interfaces for a that implements them diff --git a/LightweightIocContainer/Interfaces/Registrations/IOpenGenericRegistration.cs b/LightweightIocContainer/Interfaces/Registrations/IOpenGenericRegistration.cs index 4081365..4aaebc4 100644 --- a/LightweightIocContainer/Interfaces/Registrations/IOpenGenericRegistration.cs +++ b/LightweightIocContainer/Interfaces/Registrations/IOpenGenericRegistration.cs @@ -6,8 +6,14 @@ using System; namespace LightweightIocContainer.Interfaces.Registrations { + /// + /// for open generic types + /// public interface IOpenGenericRegistration : IRegistration, ILifestyleProvider { + /// + /// The that implements the that is registered with this + /// Type ImplementationType { get; } } } \ No newline at end of file diff --git a/LightweightIocContainer/IocContainer.cs b/LightweightIocContainer/IocContainer.cs index c93abe1..c95a555 100644 --- a/LightweightIocContainer/IocContainer.cs +++ b/LightweightIocContainer/IocContainer.cs @@ -68,6 +68,15 @@ namespace LightweightIocContainer return registration; } + /// + /// Register an open generic Interface with an open generic Type that implements it + /// + /// The open generic Interface to register + /// The open generic Type that implements the interface + /// The for this + /// The created + /// Function can only be used to register open generic types + /// Can't register a multiton with open generic registration public IOpenGenericRegistration RegisterOpenGenerics(Type tInterface, Type tImplementation, Lifestyle lifestyle = Lifestyle.Transient) { if (!tInterface.ContainsGenericParameters) diff --git a/LightweightIocContainer/LightweightIocContainer.xml b/LightweightIocContainer/LightweightIocContainer.xml index 331e407..a2891e6 100644 --- a/LightweightIocContainer/LightweightIocContainer.xml +++ b/LightweightIocContainer/LightweightIocContainer.xml @@ -86,6 +86,17 @@ The constructor that does not match + + + Could not find generic method + + + + + Could not find generic method + + The name of the generic method + The creation of the abstract method is illegal in its current state @@ -274,6 +285,24 @@ The implemented abstract typed factory/> + + + Helper class to call a generic method without generic type parameters + + + + + Call a generic method without generic type parameters + + The caller of the method + The name of the method to call + The generic parameter as parameter + The to find the method + The parameters of the method + The result of invoking the method + Could not find the generic method + Any thrown after invoking the generic method + An that installs all s for its given @@ -346,6 +375,15 @@ The for this The created + + + Register an open generic Interface with an open generic Type that implements it + + The open generic Interface to register + The open generic Type that implements the interface + The for this + The created + Register multiple interfaces for a that implements them @@ -609,6 +647,16 @@ The registered interface The registered implementation + + + for open generic types + + + + + The that implements the that is registered with this + + The base registration that is used to register an Interface @@ -705,6 +753,17 @@ The for this The created + + + Register an open generic Interface with an open generic Type that implements it + + The open generic Interface to register + The open generic Type that implements the interface + The for this + The created + Function can only be used to register open generic types + Can't register a multiton with open generic registration + Register multiple interfaces for a that implements them @@ -1078,6 +1137,39 @@ The of the multiton scope + + + for open generic types + + + + + for open generic types + + The of the interface + The of the implementation type + The of this + + + + The name of the + + + + + The of the Interface that is registered with this + + + + + The that implements the that is registered with this + + + + + The Lifestyle of Instances that are created with this + + The that is used to register an Interface diff --git a/LightweightIocContainer/Properties/AssemblyInfo.cs b/LightweightIocContainer/Properties/AssemblyInfo.cs index 581d540..18bea16 100644 --- a/LightweightIocContainer/Properties/AssemblyInfo.cs +++ b/LightweightIocContainer/Properties/AssemblyInfo.cs @@ -4,8 +4,4 @@ using System.Runtime.CompilerServices; -[assembly:InternalsVisibleTo("Test.LightweightIocContainer")] - -namespace LightweightIocContainer.Properties -{ -} \ No newline at end of file +[assembly:InternalsVisibleTo("Test.LightweightIocContainer")] \ No newline at end of file diff --git a/LightweightIocContainer/Registrations/OpenGenericRegistration.cs b/LightweightIocContainer/Registrations/OpenGenericRegistration.cs index 03a51f1..df37b4f 100644 --- a/LightweightIocContainer/Registrations/OpenGenericRegistration.cs +++ b/LightweightIocContainer/Registrations/OpenGenericRegistration.cs @@ -7,8 +7,17 @@ using LightweightIocContainer.Interfaces.Registrations; namespace LightweightIocContainer.Registrations { + /// + /// for open generic types + /// public class OpenGenericRegistration : IOpenGenericRegistration { + /// + /// for open generic types + /// + /// The of the interface + /// The of the implementation type + /// The of this public OpenGenericRegistration(Type interfaceType, Type implementationType, Lifestyle lifestyle) { InterfaceType = interfaceType; @@ -18,9 +27,24 @@ namespace LightweightIocContainer.Registrations Name = $"{InterfaceType.Name}, {ImplementationType.Name}, Lifestyle: {Lifestyle.ToString()}"; } + /// + /// The name of the + /// public string Name { get; } + + /// + /// The of the Interface that is registered with this + /// public Type InterfaceType { get; } + + /// + /// The that implements the that is registered with this + /// public Type ImplementationType { get; } + + /// + /// The Lifestyle of Instances that are created with this + /// public Lifestyle Lifestyle { get; } } } \ No newline at end of file diff --git a/Test.LightweightIocContainer/EnumerableExtensionTest.cs b/Test.LightweightIocContainer/EnumerableExtensionTest.cs index ddc724c..0540ac2 100644 --- a/Test.LightweightIocContainer/EnumerableExtensionTest.cs +++ b/Test.LightweightIocContainer/EnumerableExtensionTest.cs @@ -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 list = new List(); @@ -51,6 +53,7 @@ namespace Test.LightweightIocContainer } [Test] + [SuppressMessage("ReSharper", "CollectionNeverUpdated.Local")] public void TestFirstOrGivenPredicateEmpty() { List list = new List(); diff --git a/Test.LightweightIocContainer/IocContainerRecursionTest.cs b/Test.LightweightIocContainer/IocContainerRecursionTest.cs index 9a0c069..0e3e772 100644 --- a/Test.LightweightIocContainer/IocContainerRecursionTest.cs +++ b/Test.LightweightIocContainer/IocContainerRecursionTest.cs @@ -141,6 +141,7 @@ namespace Test.LightweightIocContainer _iocContainer.Register(); IA a = _iocContainer.Resolve(); + Assert.IsNotNull(a); } [Test] diff --git a/Test.LightweightIocContainer/OpenGenericRegistrationTest.cs b/Test.LightweightIocContainer/OpenGenericRegistrationTest.cs index 391a96a..e1b87d7 100644 --- a/Test.LightweightIocContainer/OpenGenericRegistrationTest.cs +++ b/Test.LightweightIocContainer/OpenGenericRegistrationTest.cs @@ -2,6 +2,7 @@ // Created: 2020-09-18 // Copyright(c) 2020 SimonG. All Rights Reserved. +using System.Diagnostics.CodeAnalysis; using JetBrains.Annotations; using LightweightIocContainer; using LightweightIocContainer.Exceptions; @@ -16,6 +17,7 @@ namespace Test.LightweightIocContainer private IIocContainer _iocContainer; [UsedImplicitly] + [SuppressMessage("ReSharper", "UnusedTypeParameter")] public interface ITest {