diff --git a/LightweightIocContainer/Exceptions/UnknownRegistrationException.cs b/LightweightIocContainer/Exceptions/UnknownRegistrationException.cs index 0a83286..50b25c2 100644 --- a/LightweightIocContainer/Exceptions/UnknownRegistrationException.cs +++ b/LightweightIocContainer/Exceptions/UnknownRegistrationException.cs @@ -8,12 +8,12 @@ using LightweightIocContainer.Interfaces.Registrations; namespace LightweightIocContainer.Exceptions { /// - /// An unknown was used + /// An unknown was used /// internal class UnknownRegistrationException : Exception { /// - /// An unknown was used + /// An unknown was used /// /// The exception message public UnknownRegistrationException(string message) diff --git a/LightweightIocContainer/Interfaces/IIocContainer.cs b/LightweightIocContainer/Interfaces/IIocContainer.cs index afa8af9..0b5d2bd 100644 --- a/LightweightIocContainer/Interfaces/IIocContainer.cs +++ b/LightweightIocContainer/Interfaces/IIocContainer.cs @@ -3,14 +3,13 @@ // Copyright(c) 2019 SimonG. All Rights Reserved. using System; -using LightweightIocContainer.Exceptions; using LightweightIocContainer.Interfaces.Installers; using LightweightIocContainer.Interfaces.Registrations; namespace LightweightIocContainer.Interfaces { /// - /// The main container that carries all the s and can resolve all the types you'll ever want + /// The main container that carries all the s and can resolve all the types you'll ever want /// public interface IIocContainer : IDisposable { @@ -26,17 +25,17 @@ namespace LightweightIocContainer.Interfaces /// /// The Interface to register /// The Type that implements the interface - /// The for this - /// The created + /// The for this + /// The created IDefaultRegistration Register(Lifestyle lifestyle = Lifestyle.Transient) where TImplementation : TInterface; /// /// Register a without an interface /// /// The to register - /// The for this - /// The created - IDefaultRegistration Register(Lifestyle lifestyle = Lifestyle.Transient); + /// The for this + /// The created + ISingleTypeRegistration Register(Lifestyle lifestyle = Lifestyle.Transient); /// /// Register an Interface with a Type that implements it as a multiton @@ -44,14 +43,14 @@ namespace LightweightIocContainer.Interfaces /// The Interface to register /// The Type that implements the interface /// The Type of the multiton scope - /// The created + /// The created IMultitonRegistration Register() where TImplementation : TInterface; /// /// Register an Interface as an abstract typed factory /// /// The abstract typed factory to register - /// The created + /// The created ITypedFactoryRegistration RegisterFactory(); /// @@ -59,7 +58,8 @@ namespace LightweightIocContainer.Interfaces /// /// The Interface to register /// The for the callback - /// The created + /// The created + [Obsolete("RegisterUnitTestCallback is deprecated, use `WithFactoryMethod()` from ISingleTypeRegistration instead.")] IUnitTestCallbackRegistration RegisterUnitTestCallback(ResolveCallback unitTestCallback); /// diff --git a/LightweightIocContainer/Interfaces/Installers/IIocInstaller.cs b/LightweightIocContainer/Interfaces/Installers/IIocInstaller.cs index fb99ce6..d329bd4 100644 --- a/LightweightIocContainer/Interfaces/Installers/IIocInstaller.cs +++ b/LightweightIocContainer/Interfaces/Installers/IIocInstaller.cs @@ -12,7 +12,7 @@ namespace LightweightIocContainer.Interfaces.Installers public interface IIocInstaller { /// - /// Install the needed s in the given + /// Install the needed s in the given /// /// The current void Install(IIocContainer container); diff --git a/LightweightIocContainer/Interfaces/Registrations/IDefaultRegistration.cs b/LightweightIocContainer/Interfaces/Registrations/IDefaultRegistration.cs index 6c57fd4..3597927 100644 --- a/LightweightIocContainer/Interfaces/Registrations/IDefaultRegistration.cs +++ b/LightweightIocContainer/Interfaces/Registrations/IDefaultRegistration.cs @@ -1,39 +1,20 @@ -// Author: simon.gockner -// Created: 2019-05-20 +// Author: Gockner, Simon +// Created: 2019-11-22 // Copyright(c) 2019 SimonG. All Rights Reserved. using System; -using LightweightIocContainer.Interfaces.Installers; namespace LightweightIocContainer.Interfaces.Registrations { /// - /// The default registration that is used to register a for the Interface it implements + /// The to register a for the Interface it implements /// - /// The registered Interface - public interface IDefaultRegistration : IRegistrationBase + /// The of the interface + public interface IDefaultRegistration : IRegistrationBase { /// - /// The that implements the that is registered with this + /// The that implements the that is registered with this /// Type ImplementationType { get; } - - /// - /// The Lifestyle of Instances that are created with this - /// - Lifestyle Lifestyle { get; } - - /// - /// This is invoked when an instance of this type is created. - /// Can be set in the by calling - /// - Action OnCreateAction { get; } - - /// - /// Pass an that will be invoked when an instance of this type is created - /// - /// The - /// The current instance of this - IDefaultRegistration OnCreate(Action action); } } \ No newline at end of file diff --git a/LightweightIocContainer/Interfaces/Registrations/IRegistration.cs b/LightweightIocContainer/Interfaces/Registrations/IRegistration.cs new file mode 100644 index 0000000..65d6dd6 --- /dev/null +++ b/LightweightIocContainer/Interfaces/Registrations/IRegistration.cs @@ -0,0 +1,24 @@ +// Author: simon.gockner +// Created: 2019-05-20 +// Copyright(c) 2019 SimonG. All Rights Reserved. + +using System; + +namespace LightweightIocContainer.Interfaces.Registrations +{ + /// + /// The base registration that is used to register an Interface + /// + public interface IRegistration + { + /// + /// The name of the + /// + string Name { get; } + + /// + /// The of the Interface that is registered with this + /// + Type InterfaceType { get; } + } +} \ No newline at end of file diff --git a/LightweightIocContainer/Interfaces/Registrations/IRegistrationBase.cs b/LightweightIocContainer/Interfaces/Registrations/IRegistrationBase.cs index cc39e41..7f7e3dd 100644 --- a/LightweightIocContainer/Interfaces/Registrations/IRegistrationBase.cs +++ b/LightweightIocContainer/Interfaces/Registrations/IRegistrationBase.cs @@ -3,22 +3,58 @@ // Copyright(c) 2019 SimonG. All Rights Reserved. using System; +using LightweightIocContainer.Exceptions; +using LightweightIocContainer.Interfaces.Installers; namespace LightweightIocContainer.Interfaces.Registrations { /// - /// The base registration that is used to register an Interface + /// The that is used to register an Interface /// - public interface IRegistrationBase + /// The registered Interface + public interface IRegistrationBase : IRegistration { /// - /// The name of the + /// The Lifestyle of Instances that are created with this /// - string Name { get; } + Lifestyle Lifestyle { get; } /// - /// The of the Interface that is registered with this + /// This is invoked when an instance of this type is created. + /// Can be set in the by calling /// - Type InterfaceType { get; } + Action OnCreateAction { get; } + + /// + /// Pass an that will be invoked when an instance of this type is created + /// + /// The + /// The current instance of this + IRegistrationBase OnCreate(Action action); + + /// + /// An of parameters that are used to an instance of this + /// Can be set in the by calling + /// + object[] Parameters { get; } + + /// + /// Pass parameters that will be used to an instance of this + /// Parameters set with this method are always inserted at the beginning of the argument list if more parameters are given when resolving + /// + /// The parameters + /// The current instance of this + /// are already set or no parameters given + IRegistrationBase WithParameters(params object[] parameters); + + /// + /// Pass parameters that will be used to an instance of this + /// Parameters set with this method are inserted at the position in the argument list that is passed with the parameter if more parameters are given when resolving + /// + /// The parameters with their position + /// The current instance of this + /// are already set or no parameters given + IRegistrationBase WithParameters(params (int index, object parameter)[] parameters); + } } \ No newline at end of file diff --git a/LightweightIocContainer/Interfaces/Registrations/ISingleTypeRegistration.cs b/LightweightIocContainer/Interfaces/Registrations/ISingleTypeRegistration.cs new file mode 100644 index 0000000..ad9f188 --- /dev/null +++ b/LightweightIocContainer/Interfaces/Registrations/ISingleTypeRegistration.cs @@ -0,0 +1,27 @@ +// Author: Gockner, Simon +// Created: 2019-11-22 +// Copyright(c) 2019 SimonG. All Rights Reserved. + +using System; + +namespace LightweightIocContainer.Interfaces.Registrations +{ + /// + /// The to register either only an interface or only a + /// + /// The of the + public interface ISingleTypeRegistration : IRegistrationBase + { + /// + /// that is invoked instead of creating an instance of this the default way + /// + Func FactoryMethod { get; } + + /// + /// Pass a that will be invoked instead of creating an instance of this the default way + /// + /// The + /// The current instance of this + ISingleTypeRegistration WithFactoryMethod(Func factoryMethod); + } +} \ No newline at end of file diff --git a/LightweightIocContainer/Interfaces/Registrations/ITypedFactoryRegistration.cs b/LightweightIocContainer/Interfaces/Registrations/ITypedFactoryRegistration.cs index 584a290..12c361e 100644 --- a/LightweightIocContainer/Interfaces/Registrations/ITypedFactoryRegistration.cs +++ b/LightweightIocContainer/Interfaces/Registrations/ITypedFactoryRegistration.cs @@ -10,7 +10,7 @@ namespace LightweightIocContainer.Interfaces.Registrations /// The registration that is used to register an abstract typed factory /// /// The type of the abstract typed factory - public interface ITypedFactoryRegistration : IRegistrationBase + public interface ITypedFactoryRegistration : IRegistration { /// /// The class that contains the implemented abstract factory of this diff --git a/LightweightIocContainer/Interfaces/Registrations/IUnitTestCallbackRegistration.cs b/LightweightIocContainer/Interfaces/Registrations/IUnitTestCallbackRegistration.cs index e5831d8..d10f74e 100644 --- a/LightweightIocContainer/Interfaces/Registrations/IUnitTestCallbackRegistration.cs +++ b/LightweightIocContainer/Interfaces/Registrations/IUnitTestCallbackRegistration.cs @@ -2,17 +2,21 @@ // Created: 2019-10-15 // Copyright(c) 2019 SimonG. All Rights Reserved. +using System; + namespace LightweightIocContainer.Interfaces.Registrations { /// - /// A special that allows to set a as a callback that is called on + /// A special that allows to set a as a callback that is called on /// /// - public interface IUnitTestCallbackRegistration : IRegistrationBase + [Obsolete("IUnitTestCallbackRegistration is deprecated, use `WithFactoryMethod()` from ISingleTypeRegistration instead.")] + public interface IUnitTestCallbackRegistration : IRegistration { /// /// An that is set as a callback that is called on /// + [Obsolete("UnitTestResolveCallback is deprecated, use `WithFactoryMethod()` from ISingleTypeRegistration instead.")] ResolveCallback UnitTestResolveCallback { get; } } } \ No newline at end of file diff --git a/LightweightIocContainer/InternalResolvePlaceholder.cs b/LightweightIocContainer/InternalResolvePlaceholder.cs new file mode 100644 index 0000000..8f97059 --- /dev/null +++ b/LightweightIocContainer/InternalResolvePlaceholder.cs @@ -0,0 +1,14 @@ +// Author: Gockner, Simon +// Created: 2019-11-22 +// Copyright(c) 2019 SimonG. All Rights Reserved. + +namespace LightweightIocContainer +{ + /// + /// An internal placeholder that is used during the resolving process + /// + internal class InternalResolvePlaceholder + { + + } +} \ No newline at end of file diff --git a/LightweightIocContainer/IocContainer.cs b/LightweightIocContainer/IocContainer.cs index 0112cfd..dd6b580 100644 --- a/LightweightIocContainer/IocContainer.cs +++ b/LightweightIocContainer/IocContainer.cs @@ -17,19 +17,19 @@ using LightweightIocContainer.Registrations; namespace LightweightIocContainer { /// - /// The main container that carries all the s and can resolve all the types you'll ever want + /// The main container that carries all the s and can resolve all the types you'll ever want /// public class IocContainer : IIocContainer { private readonly RegistrationFactory _registrationFactory; - private readonly List _registrations = new List(); + private readonly List _registrations = new List(); private readonly List<(Type type, object instance)> _singletons = new List<(Type, object)>(); private readonly List<(Type type, Type scope, ConditionalWeakTable instances)> _multitons = new List<(Type, Type, ConditionalWeakTable)>(); /// - /// The main container that carries all the s and can resolve all the types you'll ever want + /// The main container that carries all the s and can resolve all the types you'll ever want /// public IocContainer() { @@ -57,8 +57,8 @@ namespace LightweightIocContainer /// /// The Interface to register /// The Type that implements the interface - /// The for this - /// The created + /// The for this + /// The created public IDefaultRegistration Register(Lifestyle lifestyle = Lifestyle.Transient) where TImplementation : TInterface { IDefaultRegistration registration = _registrationFactory.Register(lifestyle); @@ -71,11 +71,11 @@ namespace LightweightIocContainer /// Register a without an interface /// /// The to register - /// The for this - /// The created - public IDefaultRegistration Register(Lifestyle lifestyle = Lifestyle.Transient) + /// The for this + /// The created + public ISingleTypeRegistration Register(Lifestyle lifestyle = Lifestyle.Transient) { - IDefaultRegistration registration = _registrationFactory.Register(lifestyle); + ISingleTypeRegistration registration = _registrationFactory.Register(lifestyle); Register(registration); return registration; @@ -87,7 +87,7 @@ namespace LightweightIocContainer /// The Interface to register /// The Type that implements the interface /// The Type of the multiton scope - /// The created + /// The created public IMultitonRegistration Register() where TImplementation : TInterface { IMultitonRegistration registration = _registrationFactory.Register(); @@ -100,7 +100,7 @@ namespace LightweightIocContainer /// Register an Interface as an abstract typed factory /// /// The abstract typed factory to register - /// The created + /// The created public ITypedFactoryRegistration RegisterFactory() { ITypedFactoryRegistration registration = _registrationFactory.RegisterFactory(); @@ -114,7 +114,8 @@ namespace LightweightIocContainer /// /// The Interface to register /// The for the callback - /// The created + /// The created + [Obsolete("RegisterUnitTestCallback is deprecated, use `WithFactoryMethod()` from ISingleTypeRegistration instead.")] public IUnitTestCallbackRegistration RegisterUnitTestCallback(ResolveCallback unitTestCallback) { IUnitTestCallbackRegistration registration = _registrationFactory.RegisterUnitTestCallback(unitTestCallback); @@ -124,11 +125,11 @@ namespace LightweightIocContainer } /// - /// Add the to the the + /// Add the to the the /// - /// The given + /// The given /// The is already registered in this - private void Register(IRegistrationBase registration) + private void Register(IRegistration registration) { //if type is already registered if (_registrations.Any(r => r.InterfaceType == registration.InterfaceType)) @@ -195,7 +196,7 @@ namespace LightweightIocContainer /// The registration for the given has an unknown private T ResolveInternal(object[] arguments, List resolveStack = null) { - IRegistrationBase registration = _registrations.FirstOrDefault(r => r.InterfaceType == typeof(T)); + IRegistration registration = _registrations.FirstOrDefault(r => r.InterfaceType == typeof(T)); if (registration == null) throw new TypeNotRegisteredException(typeof(T)); @@ -209,11 +210,14 @@ namespace LightweightIocContainer T resolvedInstance; + //TODO: remove this #pragma when IUnitTestCallbackRegistration is removed +#pragma warning disable 618 if (registration is IUnitTestCallbackRegistration unitTestCallbackRegistration) { resolvedInstance = unitTestCallbackRegistration.UnitTestResolveCallback.Invoke(arguments); } - else if (registration is IDefaultRegistration defaultRegistration) +#pragma warning restore 618 + else if (registration is IRegistrationBase defaultRegistration) { if (defaultRegistration.Lifestyle == Lifestyle.Singleton) resolvedInstance = GetOrCreateSingletonInstance(defaultRegistration, arguments, resolveStack); @@ -242,7 +246,7 @@ namespace LightweightIocContainer /// The arguments to resolve /// The current resolve stack /// An existing or newly created singleton instance of the given - private T GetOrCreateSingletonInstance(IDefaultRegistration registration, object[] arguments, List resolveStack) + private T GetOrCreateSingletonInstance(IRegistrationBase registration, object[] arguments, List resolveStack) { //if a singleton instance exists return it object instance = _singletons.FirstOrDefault(s => s.type == typeof(T)).instance; @@ -306,15 +310,82 @@ namespace LightweightIocContainer /// The constructor arguments /// The current resolve stack /// A newly created instance of the given - private T CreateInstance(IDefaultRegistration registration, object[] arguments, List resolveStack) + private T CreateInstance(IRegistrationBase registration, object[] arguments, List resolveStack) { - arguments = ResolveConstructorArguments(registration.ImplementationType, arguments, resolveStack); - T instance = (T) Activator.CreateInstance(registration.ImplementationType, arguments); + if (registration.Parameters != null) + arguments = UpdateArgumentsWithRegistrationParameters(registration, arguments); + + T instance; + if (registration is IDefaultRegistration defaultRegistration) + { + arguments = ResolveConstructorArguments(defaultRegistration.ImplementationType, arguments, resolveStack); + instance = (T) Activator.CreateInstance(defaultRegistration.ImplementationType, arguments); + } + else if (registration is ISingleTypeRegistration singleTypeRegistration) + { + if (singleTypeRegistration.InterfaceType.IsInterface && singleTypeRegistration.FactoryMethod == null) + throw new InvalidRegistrationException($"Can't register an interface without its implementation type or without a factory method (Type: {singleTypeRegistration.InterfaceType})."); + + if (singleTypeRegistration.FactoryMethod == null) //type registration without interface -> just create this type + { + arguments = ResolveConstructorArguments(singleTypeRegistration.InterfaceType, arguments, resolveStack); + instance = (T)Activator.CreateInstance(singleTypeRegistration.InterfaceType, arguments); + } + else //factory method set to create the instance + instance = singleTypeRegistration.FactoryMethod(this); + } + else + throw new UnknownRegistrationException($"There is no registration of type {registration.GetType().Name}."); + registration.OnCreateAction?.Invoke(instance); //TODO: Allow async OnCreateAction? return instance; } + /// + /// Update the given arguments with the of the given + /// + /// The given + /// The of the given + /// The constructor arguments + /// The argument list updated with the + private object[] UpdateArgumentsWithRegistrationParameters(IRegistrationBase registration, object[] arguments) + { + if (arguments != null && arguments.Any()) //if more arguments were passed to resolve + { + int argumentsSize = registration.Parameters.Length + arguments.Length; + object[] newArguments = new object[argumentsSize]; + + for (int i = 0; i < argumentsSize; i++) + { + if (i < registration.Parameters.Length) //if `i` is bigger than the length of the parameters, take the given arguments + { + object currentParameter = registration.Parameters[i]; + if (!(currentParameter is InternalResolvePlaceholder)) //use the parameter at the current index if it is not a placeholder + { + newArguments[i] = currentParameter; + continue; + } + } + + object firstArgument = arguments.FirstOrGiven(a => !(a is InternalResolvePlaceholder)); //find the first argument that is not a placeholder + if (firstArgument is InternalResolvePlaceholder) //no more arguments available + break; //there won't be any more arguments + + newArguments[i] = firstArgument; + + int indexOfFirstArgument = Array.IndexOf(arguments, firstArgument); + arguments[indexOfFirstArgument] = new InternalResolvePlaceholder(); + } + + arguments = newArguments; + } + else //no more arguments were passed to resolve -> only use parameters set during registration + arguments = registration.Parameters; + + return arguments; + } + /// /// Resolve the missing constructor arguments /// @@ -432,13 +503,5 @@ namespace LightweightIocContainer _singletons.Clear(); _multitons.Clear(); } - - /// - /// An internal placeholder that is used during the resolving process - /// - private class InternalResolvePlaceholder - { - - } } } \ No newline at end of file diff --git a/LightweightIocContainer/Lifestyle.cs b/LightweightIocContainer/Lifestyle.cs index d3dc7fc..a7141d3 100644 --- a/LightweightIocContainer/Lifestyle.cs +++ b/LightweightIocContainer/Lifestyle.cs @@ -7,7 +7,7 @@ using LightweightIocContainer.Interfaces.Registrations; namespace LightweightIocContainer { /// - /// The Lifestyles that can be used for a + /// The Lifestyles that can be used for a /// public enum Lifestyle { diff --git a/LightweightIocContainer/LightweightIocContainer.xml b/LightweightIocContainer/LightweightIocContainer.xml index e0c48cb..067c4f7 100644 --- a/LightweightIocContainer/LightweightIocContainer.xml +++ b/LightweightIocContainer/LightweightIocContainer.xml @@ -222,12 +222,12 @@ - An unknown was used + An unknown was used - An unknown was used + An unknown was used The exception message @@ -295,7 +295,7 @@ - The main container that carries all the s and can resolve all the types you'll ever want + The main container that carries all the s and can resolve all the types you'll ever want @@ -311,16 +311,16 @@ The Interface to register The Type that implements the interface - The for this - The created + The for this + The created Register a without an interface The to register - The for this - The created + The for this + The created @@ -329,14 +329,14 @@ The Interface to register The Type that implements the interface The Type of the multiton scope - The created + The created Register an Interface as an abstract typed factory The abstract typed factory to register - The created + The created @@ -344,7 +344,7 @@ The Interface to register The for the callback - The created + The created @@ -391,65 +391,113 @@ - Install the needed s in the given + Install the needed s in the given The current - The default registration that is used to register a for the Interface it implements + The to register a for the Interface it implements - The registered Interface + The of the interface - The that implements the that is registered with this + The that implements the that is registered with this + + + + + The registration that is used to register a multiton + + The registered interface + + + + The of the multiton scope + + + + + The base registration that is used to register an Interface + + + + + The name of the + + + + + The of the Interface that is registered with this + + + + + The that is used to register an Interface + The registered Interface - + - The Lifestyle of Instances that are created with this + The Lifestyle of Instances that are created with this - + This is invoked when an instance of this type is created. - Can be set in the by calling + Can be set in the by calling - + Pass an that will be invoked when an instance of this type is created The - The current instance of this + The current instance of this - + - The registration that is used to register a multiton + An of parameters that are used to an instance of this + Can be set in the by calling - The registered interface - + - The of the multiton scope + Pass parameters that will be used to an instance of this + Parameters set with this method are always inserted at the beginning of the argument list if more parameters are given when resolving + The parameters + The current instance of this + are already set or no parameters given - + - The base registration that is used to register an Interface + Pass parameters that will be used to an instance of this + Parameters set with this method are inserted at the position in the argument list that is passed with the parameter if more parameters are given when resolving + The parameters with their position + The current instance of this + are already set or no parameters given - + - The name of the + The to register either only an interface or only a + The of the - + - The of the Interface that is registered with this + that is invoked instead of creating an instance of this the default way + + + Pass a that will be invoked instead of creating an instance of this the default way + + The + The current instance of this + The registration that is used to register an abstract typed factory @@ -463,7 +511,7 @@ - A special that allows to set a as a callback that is called on + A special that allows to set a as a callback that is called on @@ -472,14 +520,19 @@ An that is set as a callback that is called on + + + An internal placeholder that is used during the resolving process + + - The main container that carries all the s and can resolve all the types you'll ever want + The main container that carries all the s and can resolve all the types you'll ever want - The main container that carries all the s and can resolve all the types you'll ever want + The main container that carries all the s and can resolve all the types you'll ever want @@ -495,16 +548,16 @@ The Interface to register The Type that implements the interface - The for this - The created + The for this + The created Register a without an interface The to register - The for this - The created + The for this + The created @@ -513,14 +566,14 @@ The Interface to register The Type that implements the interface The Type of the multiton scope - The created + The created Register an Interface as an abstract typed factory The abstract typed factory to register - The created + The created @@ -528,13 +581,13 @@ The Interface to register The for the callback - The created + The created - + - Add the to the the + Add the to the the - The given + The given The is already registered in this @@ -573,7 +626,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 @@ -595,7 +648,7 @@ No arguments given Scope argument not given - + Creates an instance of a given @@ -605,6 +658,15 @@ The current resolve stack A newly created instance of the given + + + Update the given arguments with the of the given + + The given + The of the given + The constructor arguments + The argument list updated with the + Resolve the missing constructor arguments @@ -633,14 +695,9 @@ The method - - - An internal placeholder that is used during the resolving process - - - The Lifestyles that can be used for a + The Lifestyles that can be used for a @@ -660,73 +717,110 @@ - The default registration that is used to register a for the Interface it implements + The to register a for the Interface it implements - The registered Interface + The of the interface - The default registration that is used to register a for the Interface it implements + The to register a for the Interface it implements + + The of the interface + The of the implementation + The of the + + + + The that implements the that is registered with this + + + + + The registration that is used to register a multiton + + The registered interface + + + + The registration that is used to register a multiton The of the Interface The of the Implementation - The of the registration + The of the Multiton Scope - + - The name of the + The of the multiton scope - + - The of the Interface that is registered with this + The that is used to register an Interface + The registered Interface - + + + The that is used to register an Interface + + The of the Interface + The of the registration + + + + The name of the + + + - The that implements the that is registered with this + The of the Interface that is registered with this - + - The of Instances that are created with this + The of Instances that are created with this - + This is invoked when an instance of this type is created. - Can be set in the by calling + Can be set in the by calling - + Pass an that will be invoked when an instance of this is created The - The current instance of this + The current instance of this - + - The registration that is used to register a multiton + An of parameters that are used to an instance of this + Can be set in the by calling - The registered interface - + - The registration that is used to register a multiton + Pass parameters that will be used to an instance of this + Parameters set with this method are always inserted at the beginning of the argument list if more parameters are given when resolving - The of the Interface - The of the Implementation - The of the Multiton Scope + The parameters + The current instance of this + are already set or no parameters given - + - The of the multiton scope + Pass parameters that will be used to an instance of this + Parameters set with this method are inserted at the position in the argument list that is passed with the parameter if more parameters are given when resolving + The parameters with their position + The current instance of this + are already set or no parameters given - A factory to register interfaces and factories in an and create the needed s + A factory to register interfaces and factories in an and create the needed s @@ -740,11 +834,11 @@ - Register a without an interface and create a + Register a without an interface and create a - The to register - The for this - A new created with the given parameters + The to register + The for this + A new created with the given parameters @@ -762,6 +856,31 @@ The abstract typed factory to register A new created with the given parameters + + + The to register either only an interface or only a + + The of the + + + + The to register either only an interface or only a + + The of the interface or + The of the + + + + that is invoked instead of creating an instance of this the default way + + + + + Pass a that will be invoked instead of creating an instance of this the default way + + The + The current instance of this + The registration that is used to register an abstract typed factory @@ -799,13 +918,13 @@ - A special that allows to set a as a callback that is called on + A special that allows to set a as a callback that is called on - A special that allows to set a as a callback that is called on + A special that allows to set a as a callback that is called on The of the interface The that is set as a callback diff --git a/LightweightIocContainer/Registrations/DefaultRegistration.cs b/LightweightIocContainer/Registrations/DefaultRegistration.cs index 9aa0b34..f8c5c47 100644 --- a/LightweightIocContainer/Registrations/DefaultRegistration.cs +++ b/LightweightIocContainer/Registrations/DefaultRegistration.cs @@ -1,71 +1,34 @@ -// Author: simon.gockner -// Created: 2019-05-20 +// Author: Gockner, Simon +// Created: 2019-11-22 // Copyright(c) 2019 SimonG. All Rights Reserved. using System; -using LightweightIocContainer.Interfaces.Installers; using LightweightIocContainer.Interfaces.Registrations; namespace LightweightIocContainer.Registrations { /// - /// The default registration that is used to register a for the Interface it implements + /// The to register a for the Interface it implements /// - /// The registered Interface - public class DefaultRegistration : IDefaultRegistration + /// The of the interface + public class DefaultRegistration : RegistrationBase, IDefaultRegistration { /// - /// The default registration that is used to register a for the Interface it implements + /// The to register a for the Interface it implements /// - /// The of the Interface - /// The of the Implementation - /// The of the registration + /// The of the interface + /// The of the implementation + /// The of the public DefaultRegistration(Type interfaceType, Type implementationType, Lifestyle lifestyle) + : base(interfaceType, lifestyle) { - InterfaceType = interfaceType; ImplementationType = implementationType; - Lifestyle = lifestyle; - 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 + /// The that implements the that is registered with this /// public Type ImplementationType { get; } - - /// - /// The of Instances that are created with this - /// - public Lifestyle Lifestyle { get; } - - - /// - /// This is invoked when an instance of this type is created. - /// Can be set in the by calling - /// - public Action OnCreateAction { get; private set; } - - - /// - /// Pass an that will be invoked when an instance of this is created - /// - /// The - /// The current instance of this - public IDefaultRegistration OnCreate(Action action) - { - OnCreateAction = action; - return this; - } } } \ No newline at end of file diff --git a/LightweightIocContainer/Registrations/RegistrationBase.cs b/LightweightIocContainer/Registrations/RegistrationBase.cs new file mode 100644 index 0000000..512fed9 --- /dev/null +++ b/LightweightIocContainer/Registrations/RegistrationBase.cs @@ -0,0 +1,119 @@ +// Author: simon.gockner +// Created: 2019-05-20 +// Copyright(c) 2019 SimonG. All Rights Reserved. + +using System; +using System.Linq; +using LightweightIocContainer.Exceptions; +using LightweightIocContainer.Interfaces; +using LightweightIocContainer.Interfaces.Installers; +using LightweightIocContainer.Interfaces.Registrations; + +namespace LightweightIocContainer.Registrations +{ + /// + /// The that is used to register an Interface + /// + /// The registered Interface + public abstract class RegistrationBase : IRegistrationBase + { + /// + /// The that is used to register an Interface + /// + /// The of the Interface + /// The of the registration + protected RegistrationBase(Type interfaceType, Lifestyle lifestyle) + { + InterfaceType = interfaceType; + Lifestyle = lifestyle; + } + + /// + /// The name of the + /// + public string Name { get; protected set; } + + /// + /// The of the Interface that is registered with this + /// + public Type InterfaceType { get; } + + /// + /// The of Instances that are created with this + /// + public Lifestyle Lifestyle { get; } + + + /// + /// This is invoked when an instance of this type is created. + /// Can be set in the by calling + /// + public Action OnCreateAction { get; private set; } + + + /// + /// Pass an that will be invoked when an instance of this is created + /// + /// The + /// The current instance of this + public IRegistrationBase OnCreate(Action action) + { + OnCreateAction = action; + return this; + } + + /// + /// An of parameters that are used to an instance of this + /// Can be set in the by calling + /// + public object[] Parameters { get; private set; } + + /// + /// Pass parameters that will be used to an instance of this + /// Parameters set with this method are always inserted at the beginning of the argument list if more parameters are given when resolving + /// + /// The parameters + /// The current instance of this + /// are already set or no parameters given + public IRegistrationBase WithParameters(params object[] parameters) + { + if (Parameters != null) + throw new InvalidRegistrationException($"Don't use `WithParameters()` method twice (Type: {InterfaceType})."); + + if (parameters == null || !parameters.Any()) + throw new InvalidRegistrationException($"No parameters given to `WithParameters()` method (Type: {InterfaceType})."); + + Parameters = parameters; + return this; + } + + /// + /// Pass parameters that will be used to an instance of this + /// Parameters set with this method are inserted at the position in the argument list that is passed with the parameter if more parameters are given when resolving + /// + /// The parameters with their position + /// The current instance of this + /// are already set or no parameters given + public IRegistrationBase WithParameters(params (int index, object parameter)[] parameters) + { + if (Parameters != null) + throw new InvalidRegistrationException($"Don't use `WithParameters()` method twice (Type: {InterfaceType})."); + + if (parameters == null || !parameters.Any()) + throw new InvalidRegistrationException($"No parameters given to `WithParameters()` method (Type: {InterfaceType})."); + + var lastIndex = parameters.Max(p => p.index); + Parameters = new object[lastIndex + 1]; + + for (int i = 0; i < Parameters.Length; i++) + { + if (parameters.Any(p => p.index == i)) + Parameters[i] = parameters.First(p => p.index == i).parameter; + else + Parameters[i] = new InternalResolvePlaceholder(); + } + + return this; + } + } +} \ No newline at end of file diff --git a/LightweightIocContainer/Registrations/RegistrationFactory.cs b/LightweightIocContainer/Registrations/RegistrationFactory.cs index 1482424..d780413 100644 --- a/LightweightIocContainer/Registrations/RegistrationFactory.cs +++ b/LightweightIocContainer/Registrations/RegistrationFactory.cs @@ -3,7 +3,6 @@ // Copyright(c) 2019 SimonG. All Rights Reserved. using System; -using LightweightIocContainer.Exceptions; using LightweightIocContainer.Interfaces; using LightweightIocContainer.Interfaces.Installers; using LightweightIocContainer.Interfaces.Registrations; @@ -11,7 +10,7 @@ using LightweightIocContainer.Interfaces.Registrations; namespace LightweightIocContainer.Registrations { /// - /// A factory to register interfaces and factories in an and create the needed s + /// A factory to register interfaces and factories in an and create the needed s /// internal class RegistrationFactory { @@ -35,17 +34,14 @@ namespace LightweightIocContainer.Registrations } /// - /// Register a without an interface and create a + /// Register a without an interface and create a /// - /// The to register - /// The for this - /// A new created with the given parameters - public IDefaultRegistration Register(Lifestyle lifestyle) + /// The to register + /// The for this + /// A new created with the given parameters + public ISingleTypeRegistration Register(Lifestyle lifestyle) { - if (typeof(TImplementation).IsInterface) - throw new InvalidRegistrationException("Can't register an interface without its implementation type."); - - return Register(lifestyle); + return new SingleTypeRegistration(typeof(T), lifestyle); } /// @@ -70,6 +66,7 @@ namespace LightweightIocContainer.Registrations return new TypedFactoryRegistration(typeof(TFactory), _iocContainer); } + [Obsolete("RegisterUnitTestCallback is deprecated, use `WithFactoryMethod()` from ISingleTypeRegistration instead.")] public IUnitTestCallbackRegistration RegisterUnitTestCallback(ResolveCallback unitTestResolveCallback) { return new UnitTestCallbackRegistration(typeof(TInterface), unitTestResolveCallback); diff --git a/LightweightIocContainer/Registrations/SingleTypeRegistration.cs b/LightweightIocContainer/Registrations/SingleTypeRegistration.cs new file mode 100644 index 0000000..7a961c3 --- /dev/null +++ b/LightweightIocContainer/Registrations/SingleTypeRegistration.cs @@ -0,0 +1,44 @@ +// Author: Gockner, Simon +// Created: 2019-11-22 +// Copyright(c) 2019 SimonG. All Rights Reserved. + +using System; +using LightweightIocContainer.Interfaces; +using LightweightIocContainer.Interfaces.Registrations; + +namespace LightweightIocContainer.Registrations +{ + /// + /// The to register either only an interface or only a + /// + /// The of the + public class SingleTypeRegistration : RegistrationBase, ISingleTypeRegistration + { + /// + /// The to register either only an interface or only a + /// + /// The of the interface or + /// The of the + public SingleTypeRegistration(Type interfaceType, Lifestyle lifestyle) + : base(interfaceType, lifestyle) + { + Name = $"{InterfaceType.Name}, Lifestyle: {Lifestyle.ToString()}"; + } + + /// + /// that is invoked instead of creating an instance of this the default way + /// + public Func FactoryMethod { get; private set; } + + /// + /// Pass a that will be invoked instead of creating an instance of this the default way + /// + /// The + /// The current instance of this + public ISingleTypeRegistration WithFactoryMethod(Func factoryMethod) + { + FactoryMethod = factoryMethod; + return this; + } + } +} \ No newline at end of file diff --git a/LightweightIocContainer/Registrations/UnitTestCallbackRegistration.cs b/LightweightIocContainer/Registrations/UnitTestCallbackRegistration.cs index 8f6e171..c489510 100644 --- a/LightweightIocContainer/Registrations/UnitTestCallbackRegistration.cs +++ b/LightweightIocContainer/Registrations/UnitTestCallbackRegistration.cs @@ -9,13 +9,14 @@ using LightweightIocContainer.Interfaces.Registrations; namespace LightweightIocContainer.Registrations { /// - /// A special that allows to set a as a callback that is called on + /// A special that allows to set a as a callback that is called on /// /// + [Obsolete("UnitTestCallbackRegistration is deprecated, use `WithFactoryMethod()` from ISingleTypeRegistration instead.")] public class UnitTestCallbackRegistration : IUnitTestCallbackRegistration { /// - /// A special that allows to set a as a callback that is called on + /// A special that allows to set a as a callback that is called on /// /// The of the interface /// The that is set as a callback diff --git a/Test.LightweightIocContainer/AssemblyInstallerTest.cs b/Test.LightweightIocContainer/AssemblyInstallerTest.cs index 30874e0..c605328 100644 --- a/Test.LightweightIocContainer/AssemblyInstallerTest.cs +++ b/Test.LightweightIocContainer/AssemblyInstallerTest.cs @@ -25,7 +25,7 @@ namespace Test.LightweightIocContainer { public void Install(IIocContainer container) { - container.Register>(); + container.Register>(); } } @@ -54,7 +54,7 @@ namespace Test.LightweightIocContainer AssemblyInstaller assemblyInstaller = new AssemblyInstaller(assemblyMock.Object); assemblyInstaller.Install(iocContainerMock.Object); - iocContainerMock.Verify(ioc => ioc.Register>>(It.IsAny()), Times.Once); + iocContainerMock.Verify(ioc => ioc.Register>>(It.IsAny()), Times.Once); } [Test] diff --git a/Test.LightweightIocContainer/DefaultRegistrationTest.cs b/Test.LightweightIocContainer/DefaultRegistrationTest.cs deleted file mode 100644 index 70cb966..0000000 --- a/Test.LightweightIocContainer/DefaultRegistrationTest.cs +++ /dev/null @@ -1,47 +0,0 @@ -// Author: Gockner, Simon -// Created: 2019-06-06 -// Copyright(c) 2019 SimonG. All Rights Reserved. - -using System; -using LightweightIocContainer; -using LightweightIocContainer.Interfaces; -using LightweightIocContainer.Interfaces.Registrations; -using LightweightIocContainer.Registrations; -using Moq; -using NUnit.Framework; - -namespace Test.LightweightIocContainer -{ - [TestFixture] - public class DefaultRegistrationTest - { - #region TestClasses - - private interface ITest - { - void DoSomething(); - } - - private class Test : ITest - { - public void DoSomething() - { - throw new Exception(); - } - } - - #endregion - - - [Test] - public void TestOnCreate() - { - RegistrationFactory registrationFactory = new RegistrationFactory(new Mock().Object); - IDefaultRegistration testRegistration = registrationFactory.Register(Lifestyle.Transient).OnCreate(t => t.DoSomething()); - - ITest test = new Test(); - - Assert.Throws(() => testRegistration.OnCreateAction(test)); - } - } -} \ No newline at end of file diff --git a/Test.LightweightIocContainer/IocContainerParameterRegistrationTest.cs b/Test.LightweightIocContainer/IocContainerParameterRegistrationTest.cs new file mode 100644 index 0000000..be23d2e --- /dev/null +++ b/Test.LightweightIocContainer/IocContainerParameterRegistrationTest.cs @@ -0,0 +1,169 @@ +// Author: Gockner, Simon +// Created: 2019-11-22 +// Copyright(c) 2019 SimonG. All Rights Reserved. + +using JetBrains.Annotations; +using LightweightIocContainer; +using LightweightIocContainer.Interfaces; +using NUnit.Framework; + +namespace Test.LightweightIocContainer +{ + [TestFixture] + // ReSharper disable MemberHidesStaticFromOuterClass + public class IocContainerParameterRegistrationTest + { + #region TestClasses + + [UsedImplicitly] + public interface IA + { + IB B { get; } + IC C { get; } + } + + [UsedImplicitly] + public interface IB + { + + } + + [UsedImplicitly] + public interface IC + { + + } + + [UsedImplicitly] + public interface ID + { + IA A { get; } + IA A2 { get; } + IB B { get; } + IC C { get; } + } + + [UsedImplicitly] + private class A : IA + { + public A(IB b, IC c) + { + B = b; + C = c; + } + + public IB B { get; } + public IC C { get; } + } + + [UsedImplicitly] + private class B : IB + { + public B(IC c) + { + } + } + + [UsedImplicitly] + private class C : IC + { + + } + + [UsedImplicitly] + private class D : ID + { + public D(IA a, IA a2, IB b, IC c) + { + A = a; + A2 = a2; + B = b; + C = c; + } + + public IA A { get; } + public IA A2 { get; } + public IB B { get; } + public IC C { get; } + } + + #endregion TestClasses + + private IIocContainer _iocContainer; + + [SetUp] + public void SetUp() + { + _iocContainer = new IocContainer(); + } + + + [TearDown] + public void TearDown() + { + _iocContainer.Dispose(); + } + + + [Test] + public void TestResolveOnlyRegistrationParameters() + { + IC c = new C(); + IB b = new B(c); + + _iocContainer.Register().WithParameters(b, c); + IA a = _iocContainer.Resolve(); + + Assert.AreEqual(b, a.B); + Assert.AreEqual(c, a.C); + } + + [Test] + public void TestResolveRegistrationAndResolveParameters() + { + IC c = new C(); + IB b = new B(c); + + _iocContainer.Register().WithParameters(b); + IA a = _iocContainer.Resolve(c); + + Assert.AreEqual(b, a.B); + Assert.AreEqual(c, a.C); + } + + [Test] + public void TestResolveRegistrationAndResolveParametersMixedOrder() + { + IC c = new C(); + IB b = new B(c); + IA a = new A(b, c); + IA a2 = new A(b, c); + + _iocContainer.Register().WithParameters((0, a), (2, b), (3, c)); + ID d = _iocContainer.Resolve(a2); + + Assert.AreEqual(a, d.A); + Assert.AreEqual(a2, d.A2); + Assert.AreEqual(b, d.B); + Assert.AreEqual(c, d.C); + } + + [Test] + public void TestResolveRegistrationParametersAndResolvedParameters() + { + IC c = new C(); + IB b = new B(c); + IA a = new A(b, c); + IA a2 = new A(b, c); + + _iocContainer.Register().WithParameters(a2); + _iocContainer.Register(); + _iocContainer.Register(); + + ID d = _iocContainer.Resolve(a); + + Assert.AreEqual(a, d.A2); + Assert.AreEqual(a2, d.A); + } + } +} \ No newline at end of file diff --git a/Test.LightweightIocContainer/IocContainerTest.cs b/Test.LightweightIocContainer/IocContainerTest.cs index 1658ab8..717255b 100644 --- a/Test.LightweightIocContainer/IocContainerTest.cs +++ b/Test.LightweightIocContainer/IocContainerTest.cs @@ -1,3 +1,4 @@ +using System; using JetBrains.Annotations; using LightweightIocContainer; using LightweightIocContainer.Exceptions; @@ -43,6 +44,11 @@ namespace Test.LightweightIocContainer void ClearMultitonInstance(); } + private interface IFoo + { + + } + private class Test : ITest { @@ -60,6 +66,11 @@ namespace Test.LightweightIocContainer { } + + public TestConstructor(IFoo foo, string name) + { + + } } [UsedImplicitly] @@ -83,6 +94,12 @@ namespace Test.LightweightIocContainer } } + [UsedImplicitly] + private class Foo : IFoo + { + + } + public class MultitonScope { @@ -166,12 +183,6 @@ namespace Test.LightweightIocContainer Assert.AreEqual(typeof(ITest), exception.Type); } - [Test] - public void TestRegisterInterfaceWithoutImplementation() - { - Assert.Throws(() => _iocContainer.Register()); - } - [Test] public void TestRegisterFactoryWithoutCreate() { @@ -185,6 +196,7 @@ namespace Test.LightweightIocContainer } [Test] + [Obsolete("RegisterUnitTestCallback is deprecated, use `WithFactoryMethod()` from ISingleTypeRegistration instead.")] public void TestRegisterUnitTestCallback() { Assert.DoesNotThrow(() => _iocContainer.RegisterUnitTestCallback(delegate {return new Test(); })); @@ -217,6 +229,13 @@ namespace Test.LightweightIocContainer Assert.IsInstanceOf(resolvedTest); } + [Test] + public void TestResolveInterfaceWithoutImplementation() + { + _iocContainer.Register(); + Assert.Throws(() => _iocContainer.Resolve()); + } + [Test] public void TestResolveWithParams() { @@ -435,6 +454,7 @@ namespace Test.LightweightIocContainer } [Test] + [Obsolete("RegisterUnitTestCallback is deprecated, use `WithFactoryMethod()` from ISingleTypeRegistration instead.")] public void TestResolveUnitTestCallbackRegistration() { ITest callbackTest = new Test(); @@ -445,6 +465,17 @@ namespace Test.LightweightIocContainer Assert.AreEqual(callbackTest, test); } + [Test] + public void TestResolveSingleTypeRegistrationWithFactoryMethod() + { + _iocContainer.Register(); + _iocContainer.Register().WithFactoryMethod(c => new TestConstructor(c.Resolve(), "someName")); + + ITest test = _iocContainer.Resolve(); + + Assert.NotNull(test); + } + [Test] public void TestIsTypeRegistered() { diff --git a/Test.LightweightIocContainer/RegistrationBaseTest.cs b/Test.LightweightIocContainer/RegistrationBaseTest.cs new file mode 100644 index 0000000..b29afa7 --- /dev/null +++ b/Test.LightweightIocContainer/RegistrationBaseTest.cs @@ -0,0 +1,119 @@ +// Author: Gockner, Simon +// Created: 2019-06-06 +// Copyright(c) 2019 SimonG. All Rights Reserved. + +using System; +using JetBrains.Annotations; +using LightweightIocContainer; +using LightweightIocContainer.Exceptions; +using LightweightIocContainer.Interfaces; +using LightweightIocContainer.Interfaces.Registrations; +using LightweightIocContainer.Registrations; +using Moq; +using NUnit.Framework; + +namespace Test.LightweightIocContainer +{ + [TestFixture] + public class RegistrationBaseTest + { + #region TestClasses + + private interface ITest + { + void DoSomething(); + } + + private interface IFoo + { + + } + + private interface IBar + { + + } + + private class Test : ITest + { + public void DoSomething() + { + throw new Exception(); + } + } + + [UsedImplicitly] + private class Foo : IFoo + { + public Foo(IBar bar, ITest test) + { + + } + } + + private class Bar : IBar + { + + } + + #endregion + + + [Test] + public void TestOnCreate() + { + RegistrationFactory registrationFactory = new RegistrationFactory(new Mock().Object); + IRegistrationBase testRegistration = registrationFactory.Register(Lifestyle.Transient).OnCreate(t => t.DoSomething()); + + ITest test = new Test(); + + Assert.Throws(() => testRegistration.OnCreateAction(test)); + } + + [Test] + public void TestWithParameters() + { + RegistrationFactory registrationFactory = new RegistrationFactory(new Mock().Object); + + IBar bar = new Bar(); + ITest test = new Test(); + + IRegistrationBase testRegistration = registrationFactory.Register(Lifestyle.Transient).WithParameters(bar, test); + + Assert.AreEqual(bar, testRegistration.Parameters[0]); + Assert.AreEqual(test, testRegistration.Parameters[1]); + } + + [Test] + public void TestWithParametersDifferentOrder() + { + RegistrationFactory registrationFactory = new RegistrationFactory(new Mock().Object); + + IBar bar = new Bar(); + ITest test = new Test(); + + IRegistrationBase testRegistration = registrationFactory.Register(Lifestyle.Transient).WithParameters((0, bar), (3, test), (2, "SomeString")); + + Assert.AreEqual(bar, testRegistration.Parameters[0]); + Assert.IsInstanceOf(testRegistration.Parameters[1]); + Assert.AreEqual("SomeString", testRegistration.Parameters[2]); + Assert.AreEqual(test, testRegistration.Parameters[3]); + } + + [Test] + public void TestWithParametersCalledTwice() + { + RegistrationFactory registrationFactory = new RegistrationFactory(new Mock().Object); + Assert.Throws(() => registrationFactory.Register(Lifestyle.Transient).WithParameters(new Bar()).WithParameters(new Test())); + Assert.Throws(() => registrationFactory.Register(Lifestyle.Transient).WithParameters((0, new Bar())).WithParameters((1, new Test()))); + } + + [Test] + public void TestWithParametersNoParametersGiven() + { + RegistrationFactory registrationFactory = new RegistrationFactory(new Mock().Object); + Assert.Throws(() => registrationFactory.Register(Lifestyle.Transient).WithParameters((object[])null)); + Assert.Throws(() => registrationFactory.Register(Lifestyle.Transient).WithParameters(((int index, object parameter)[])null)); + } + } +} \ No newline at end of file diff --git a/Test.LightweightIocContainer/SingleTypeRegistrationTest.cs b/Test.LightweightIocContainer/SingleTypeRegistrationTest.cs new file mode 100644 index 0000000..b8bf268 --- /dev/null +++ b/Test.LightweightIocContainer/SingleTypeRegistrationTest.cs @@ -0,0 +1,61 @@ +// Author: Gockner, Simon +// Created: 2019-11-22 +// Copyright(c) 2019 SimonG. All Rights Reserved. + +using JetBrains.Annotations; +using LightweightIocContainer; +using LightweightIocContainer.Interfaces; +using LightweightIocContainer.Interfaces.Registrations; +using LightweightIocContainer.Registrations; +using Moq; +using NUnit.Framework; + +namespace Test.LightweightIocContainer +{ + [TestFixture] + // ReSharper disable MemberHidesStaticFromOuterClass + public class SingleTypeRegistrationTest + { + private interface IFoo + { + IBar Bar { get; } + } + + private interface IBar + { + + } + + [UsedImplicitly] + private class Foo : IFoo + { + public Foo(IBar bar) + { + Bar = bar; + } + + public IBar Bar { get; } + } + + [UsedImplicitly] + private class Bar : IBar + { + + } + + [Test] + public void TestSingleTypeRegistrationWithFactoryMethod() + { + IBar bar = new Bar(); + + Mock iocContainerMock = new Mock(); + iocContainerMock.Setup(c => c.Resolve()).Returns(bar); + + RegistrationFactory registrationFactory = new RegistrationFactory(iocContainerMock.Object); + ISingleTypeRegistration registration = registrationFactory.Register(Lifestyle.Transient).WithFactoryMethod(c => new Foo(c.Resolve())); + + IFoo foo = registration.FactoryMethod(iocContainerMock.Object); + Assert.AreEqual(bar, foo.Bar); + } + } +} \ No newline at end of file diff --git a/Test.LightweightIocContainer/UnitTestCallbackRegistrationTest.cs b/Test.LightweightIocContainer/UnitTestCallbackRegistrationTest.cs index 0e4a099..f9392db 100644 --- a/Test.LightweightIocContainer/UnitTestCallbackRegistrationTest.cs +++ b/Test.LightweightIocContainer/UnitTestCallbackRegistrationTest.cs @@ -2,6 +2,7 @@ // Created: 2019-10-15 // Copyright(c) 2019 SimonG. All Rights Reserved. +using System; using LightweightIocContainer; using LightweightIocContainer.Interfaces; using LightweightIocContainer.Interfaces.Registrations; @@ -12,6 +13,7 @@ using NUnit.Framework; namespace Test.LightweightIocContainer { [TestFixture] + [Obsolete("UnitTestCallbackRegistration is deprecated, use `WithFactoryMethod()` from ISingleTypeRegistration instead.")] public class UnitTestCallbackRegistrationTest { private interface ITest