#29: add `WithParameters()` method to IRegistrationBase:

- pass parameters that will be used to create an instance of the registered type
- add new method `UpdateArgumentsWithRegistrationParameters()` that handles these parameters in the `CreateInstance<>()` method
pull/32/head
Simon Gockner 6 years ago
parent f1e4f5e2f9
commit 62b36cb506
  1. 26
      LightweightIocContainer/Interfaces/Registrations/IRegistrationBase.cs
  2. 14
      LightweightIocContainer/InternalResolvePlaceholder.cs
  3. 55
      LightweightIocContainer/IocContainer.cs
  4. 67
      LightweightIocContainer/LightweightIocContainer.xml
  5. 57
      LightweightIocContainer/Registrations/RegistrationBase.cs

@ -3,6 +3,7 @@
// Copyright(c) 2019 SimonG. All Rights Reserved. // Copyright(c) 2019 SimonG. All Rights Reserved.
using System; using System;
using LightweightIocContainer.Exceptions;
using LightweightIocContainer.Interfaces.Installers; using LightweightIocContainer.Interfaces.Installers;
namespace LightweightIocContainer.Interfaces.Registrations namespace LightweightIocContainer.Interfaces.Registrations
@ -30,5 +31,30 @@ namespace LightweightIocContainer.Interfaces.Registrations
/// <param name="action">The <see cref="Action{T}"/></param> /// <param name="action">The <see cref="Action{T}"/></param>
/// <returns>The current instance of this <see cref="IRegistrationBase{TInterface}"/></returns> /// <returns>The current instance of this <see cref="IRegistrationBase{TInterface}"/></returns>
IRegistrationBase<TInterface> OnCreate(Action<TInterface> action); IRegistrationBase<TInterface> OnCreate(Action<TInterface> action);
/// <summary>
/// An <see cref="Array"/> of parameters that are used to <see cref="IIocContainer.Resolve{T}()"/> an instance of this <see cref="IRegistration.InterfaceType"/>
/// <para>Can be set in the <see cref="IIocInstaller"/> by calling <see cref="WithParameters(object[])"/></para>
/// </summary>
object[] Parameters { get; }
/// <summary>
/// Pass parameters that will be used to<see cref="IIocContainer.Resolve{T}()"/> an instance of this <see cref="IRegistration.InterfaceType"/>
/// <para>Parameters set with this method are always inserted at the beginning of the argument list if more parameters are given when resolving</para>
/// </summary>
/// <param name="parameters">The parameters</param>
/// <returns>The current instance of this <see cref="IRegistrationBase{TInterface}"/></returns>
/// <exception cref="InvalidRegistrationException"><see cref="Parameters"/> are already set or no parameters given</exception>
IRegistrationBase<TInterface> WithParameters(params object[] parameters);
/// <summary>
/// Pass parameters that will be used to<see cref="IIocContainer.Resolve{T}()"/> an instance of this <see cref="IRegistration.InterfaceType"/>
/// <para>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</para>
/// </summary>
/// <param name="parameters">The parameters with their position</param>
/// <returns>The current instance of this <see cref="IRegistrationBase{TInterface}"/></returns>
/// <exception cref="InvalidRegistrationException"><see cref="Parameters"/> are already set or no parameters given</exception>
IRegistrationBase<TInterface> WithParameters(params (int index, object parameter)[] parameters);
} }
} }

@ -0,0 +1,14 @@
// Author: Gockner, Simon
// Created: 2019-11-22
// Copyright(c) 2019 SimonG. All Rights Reserved.
namespace LightweightIocContainer
{
/// <summary>
/// An internal placeholder that is used during the resolving process
/// </summary>
internal class InternalResolvePlaceholder
{
}
}

@ -312,6 +312,9 @@ namespace LightweightIocContainer
/// <returns>A newly created instance of the given <see cref="Type"/></returns> /// <returns>A newly created instance of the given <see cref="Type"/></returns>
private T CreateInstance<T>(IRegistrationBase<T> registration, object[] arguments, List<Type> resolveStack) private T CreateInstance<T>(IRegistrationBase<T> registration, object[] arguments, List<Type> resolveStack)
{ {
if (registration.Parameters != null)
arguments = UpdateArgumentsWithRegistrationParameters(registration, arguments);
T instance; T instance;
if (registration is IDefaultRegistration<T> defaultRegistration) if (registration is IDefaultRegistration<T> defaultRegistration)
{ {
@ -339,6 +342,50 @@ namespace LightweightIocContainer
return instance; return instance;
} }
/// <summary>
/// Update the given arguments with the <see cref="IRegistrationBase{TInterface}.Parameters"/> of the given <see cref="IRegistrationBase{TInterface}"/>
/// </summary>
/// <typeparam name="T">The given <see cref="Type"/></typeparam>
/// <param name="registration">The <see cref="IRegistrationBase{TInterface}"/> of the given <see cref="Type"/></param>
/// <param name="arguments">The constructor arguments</param>
/// <returns>The argument list updated with the <see cref="IRegistrationBase{TInterface}.Parameters"/></returns>
private object[] UpdateArgumentsWithRegistrationParameters<T>(IRegistrationBase<T> 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<object, InternalResolvePlaceholder>(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;
}
/// <summary> /// <summary>
/// Resolve the missing constructor arguments /// Resolve the missing constructor arguments
/// </summary> /// </summary>
@ -456,13 +503,5 @@ namespace LightweightIocContainer
_singletons.Clear(); _singletons.Clear();
_multitons.Clear(); _multitons.Clear();
} }
/// <summary>
/// An internal placeholder that is used during the resolving process
/// </summary>
private class InternalResolvePlaceholder
{
}
} }
} }

@ -456,6 +456,30 @@
<param name="action">The <see cref="T:System.Action`1"/></param> <param name="action">The <see cref="T:System.Action`1"/></param>
<returns>The current instance of this <see cref="T:LightweightIocContainer.Interfaces.Registrations.IRegistrationBase`1"/></returns> <returns>The current instance of this <see cref="T:LightweightIocContainer.Interfaces.Registrations.IRegistrationBase`1"/></returns>
</member> </member>
<member name="P:LightweightIocContainer.Interfaces.Registrations.IRegistrationBase`1.Parameters">
<summary>
An <see cref="T:System.Array"/> of parameters that are used to <see cref="M:LightweightIocContainer.Interfaces.IIocContainer.Resolve``1"/> an instance of this <see cref="P:LightweightIocContainer.Interfaces.Registrations.IRegistration.InterfaceType"/>
<para>Can be set in the <see cref="T:LightweightIocContainer.Interfaces.Installers.IIocInstaller"/> by calling <see cref="M:LightweightIocContainer.Interfaces.Registrations.IRegistrationBase`1.WithParameters(System.Object[])"/></para>
</summary>
</member>
<member name="M:LightweightIocContainer.Interfaces.Registrations.IRegistrationBase`1.WithParameters(System.Object[])">
<summary>
Pass parameters that will be used to<see cref="M:LightweightIocContainer.Interfaces.IIocContainer.Resolve``1"/> an instance of this <see cref="P:LightweightIocContainer.Interfaces.Registrations.IRegistration.InterfaceType"/>
<para>Parameters set with this method are always inserted at the beginning of the argument list if more parameters are given when resolving</para>
</summary>
<param name="parameters">The parameters</param>
<returns>The current instance of this <see cref="T:LightweightIocContainer.Interfaces.Registrations.IRegistrationBase`1"/></returns>
<exception cref="T:LightweightIocContainer.Exceptions.InvalidRegistrationException"><see cref="P:LightweightIocContainer.Interfaces.Registrations.IRegistrationBase`1.Parameters"/> are already set or no parameters given</exception>
</member>
<member name="M:LightweightIocContainer.Interfaces.Registrations.IRegistrationBase`1.WithParameters(System.ValueTuple{System.Int32,System.Object}[])">
<summary>
Pass parameters that will be used to<see cref="M:LightweightIocContainer.Interfaces.IIocContainer.Resolve``1"/> an instance of this <see cref="P:LightweightIocContainer.Interfaces.Registrations.IRegistration.InterfaceType"/>
<para>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</para>
</summary>
<param name="parameters">The parameters with their position</param>
<returns>The current instance of this <see cref="T:LightweightIocContainer.Interfaces.Registrations.IRegistrationBase`1"/></returns>
<exception cref="T:LightweightIocContainer.Exceptions.InvalidRegistrationException"><see cref="P:LightweightIocContainer.Interfaces.Registrations.IRegistrationBase`1.Parameters"/> are already set or no parameters given</exception>
</member>
<member name="T:LightweightIocContainer.Interfaces.Registrations.ISingleTypeRegistration`1"> <member name="T:LightweightIocContainer.Interfaces.Registrations.ISingleTypeRegistration`1">
<summary> <summary>
The <see cref="T:LightweightIocContainer.Interfaces.Registrations.IRegistrationBase`1"/> to register either only an interface or only a <see cref="T:System.Type"/> The <see cref="T:LightweightIocContainer.Interfaces.Registrations.IRegistrationBase`1"/> to register either only an interface or only a <see cref="T:System.Type"/>
@ -496,6 +520,11 @@
An <see cref="T:LightweightIocContainer.ResolveCallback`1"/> that is set as a callback that is called on <see cref="M:LightweightIocContainer.Interfaces.IIocContainer.Resolve``1"/> An <see cref="T:LightweightIocContainer.ResolveCallback`1"/> that is set as a callback that is called on <see cref="M:LightweightIocContainer.Interfaces.IIocContainer.Resolve``1"/>
</summary> </summary>
</member> </member>
<member name="T:LightweightIocContainer.InternalResolvePlaceholder">
<summary>
An internal placeholder that is used during the resolving process
</summary>
</member>
<member name="T:LightweightIocContainer.IocContainer"> <member name="T:LightweightIocContainer.IocContainer">
<summary> <summary>
The main container that carries all the <see cref="T:LightweightIocContainer.Interfaces.Registrations.IRegistration"/>s and can resolve all the types you'll ever want The main container that carries all the <see cref="T:LightweightIocContainer.Interfaces.Registrations.IRegistration"/>s and can resolve all the types you'll ever want
@ -629,6 +658,15 @@
<param name="resolveStack">The current resolve stack</param> <param name="resolveStack">The current resolve stack</param>
<returns>A newly created instance of the given <see cref="T:System.Type"/></returns> <returns>A newly created instance of the given <see cref="T:System.Type"/></returns>
</member> </member>
<member name="M:LightweightIocContainer.IocContainer.UpdateArgumentsWithRegistrationParameters``1(LightweightIocContainer.Interfaces.Registrations.IRegistrationBase{``0},System.Object[])">
<summary>
Update the given arguments with the <see cref="P:LightweightIocContainer.Interfaces.Registrations.IRegistrationBase`1.Parameters"/> of the given <see cref="T:LightweightIocContainer.Interfaces.Registrations.IRegistrationBase`1"/>
</summary>
<typeparam name="T">The given <see cref="T:System.Type"/></typeparam>
<param name="registration">The <see cref="T:LightweightIocContainer.Interfaces.Registrations.IRegistrationBase`1"/> of the given <see cref="T:System.Type"/></param>
<param name="arguments">The constructor arguments</param>
<returns>The argument list updated with the <see cref="P:LightweightIocContainer.Interfaces.Registrations.IRegistrationBase`1.Parameters"/></returns>
</member>
<member name="M:LightweightIocContainer.IocContainer.ResolveConstructorArguments(System.Type,System.Object[],System.Collections.Generic.List{System.Type})"> <member name="M:LightweightIocContainer.IocContainer.ResolveConstructorArguments(System.Type,System.Object[],System.Collections.Generic.List{System.Type})">
<summary> <summary>
Resolve the missing constructor arguments Resolve the missing constructor arguments
@ -657,11 +695,6 @@
The <see cref="M:System.IDisposable.Dispose"/> method The <see cref="M:System.IDisposable.Dispose"/> method
</summary> </summary>
</member> </member>
<member name="T:LightweightIocContainer.IocContainer.InternalResolvePlaceholder">
<summary>
An internal placeholder that is used during the resolving process
</summary>
</member>
<member name="T:LightweightIocContainer.Lifestyle"> <member name="T:LightweightIocContainer.Lifestyle">
<summary> <summary>
The Lifestyles that can be used for a <see cref="T:LightweightIocContainer.Interfaces.Registrations.IRegistrationBase`1"/> The Lifestyles that can be used for a <see cref="T:LightweightIocContainer.Interfaces.Registrations.IRegistrationBase`1"/>
@ -761,6 +794,30 @@
<param name="action">The <see cref="T:System.Action`1"/></param> <param name="action">The <see cref="T:System.Action`1"/></param>
<returns>The current instance of this <see cref="T:LightweightIocContainer.Interfaces.Registrations.IRegistrationBase`1"/></returns> <returns>The current instance of this <see cref="T:LightweightIocContainer.Interfaces.Registrations.IRegistrationBase`1"/></returns>
</member> </member>
<member name="P:LightweightIocContainer.Registrations.RegistrationBase`1.Parameters">
<summary>
An <see cref="T:System.Array"/> of parameters that are used to <see cref="M:LightweightIocContainer.Interfaces.IIocContainer.Resolve``1"/> an instance of this <see cref="P:LightweightIocContainer.Interfaces.Registrations.IRegistration.InterfaceType"/>
<para>Can be set in the <see cref="T:LightweightIocContainer.Interfaces.Installers.IIocInstaller"/> by calling <see cref="M:LightweightIocContainer.Registrations.RegistrationBase`1.WithParameters(System.Object[])"/></para>
</summary>
</member>
<member name="M:LightweightIocContainer.Registrations.RegistrationBase`1.WithParameters(System.Object[])">
<summary>
Pass parameters that will be used to<see cref="M:LightweightIocContainer.Interfaces.IIocContainer.Resolve``1"/> an instance of this <see cref="P:LightweightIocContainer.Interfaces.Registrations.IRegistration.InterfaceType"/>
<para>Parameters set with this method are always inserted at the beginning of the argument list if more parameters are given when resolving</para>
</summary>
<param name="parameters">The parameters</param>
<returns>The current instance of this <see cref="T:LightweightIocContainer.Interfaces.Registrations.IRegistrationBase`1"/></returns>
<exception cref="T:LightweightIocContainer.Exceptions.InvalidRegistrationException"><see cref="P:LightweightIocContainer.Registrations.RegistrationBase`1.Parameters"/> are already set or no parameters given</exception>
</member>
<member name="M:LightweightIocContainer.Registrations.RegistrationBase`1.WithParameters(System.ValueTuple{System.Int32,System.Object}[])">
<summary>
Pass parameters that will be used to<see cref="M:LightweightIocContainer.Interfaces.IIocContainer.Resolve``1"/> an instance of this <see cref="P:LightweightIocContainer.Interfaces.Registrations.IRegistration.InterfaceType"/>
<para>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</para>
</summary>
<param name="parameters">The parameters with their position</param>
<returns>The current instance of this <see cref="T:LightweightIocContainer.Interfaces.Registrations.IRegistrationBase`1"/></returns>
<exception cref="T:LightweightIocContainer.Exceptions.InvalidRegistrationException"><see cref="P:LightweightIocContainer.Registrations.RegistrationBase`1.Parameters"/> are already set or no parameters given</exception>
</member>
<member name="T:LightweightIocContainer.Registrations.RegistrationFactory"> <member name="T:LightweightIocContainer.Registrations.RegistrationFactory">
<summary> <summary>
A factory to register interfaces and factories in an <see cref="T:LightweightIocContainer.Interfaces.Installers.IIocInstaller"/> and create the needed <see cref="T:LightweightIocContainer.Interfaces.Registrations.IRegistration"/>s A factory to register interfaces and factories in an <see cref="T:LightweightIocContainer.Interfaces.Installers.IIocInstaller"/> and create the needed <see cref="T:LightweightIocContainer.Interfaces.Registrations.IRegistration"/>s

@ -3,6 +3,9 @@
// Copyright(c) 2019 SimonG. All Rights Reserved. // Copyright(c) 2019 SimonG. All Rights Reserved.
using System; using System;
using System.Linq;
using LightweightIocContainer.Exceptions;
using LightweightIocContainer.Interfaces;
using LightweightIocContainer.Interfaces.Installers; using LightweightIocContainer.Interfaces.Installers;
using LightweightIocContainer.Interfaces.Registrations; using LightweightIocContainer.Interfaces.Registrations;
@ -58,5 +61,59 @@ namespace LightweightIocContainer.Registrations
OnCreateAction = action; OnCreateAction = action;
return this; return this;
} }
/// <summary>
/// An <see cref="Array"/> of parameters that are used to <see cref="IIocContainer.Resolve{T}()"/> an instance of this <see cref="IRegistration.InterfaceType"/>
/// <para>Can be set in the <see cref="IIocInstaller"/> by calling <see cref="WithParameters(object[])"/></para>
/// </summary>
public object[] Parameters { get; private set; }
/// <summary>
/// Pass parameters that will be used to<see cref="IIocContainer.Resolve{T}()"/> an instance of this <see cref="IRegistration.InterfaceType"/>
/// <para>Parameters set with this method are always inserted at the beginning of the argument list if more parameters are given when resolving</para>
/// </summary>
/// <param name="parameters">The parameters</param>
/// <returns>The current instance of this <see cref="IRegistrationBase{TInterface}"/></returns>
/// <exception cref="InvalidRegistrationException"><see cref="Parameters"/> are already set or no parameters given</exception>
public IRegistrationBase<TInterface> 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;
}
/// <summary>
/// Pass parameters that will be used to<see cref="IIocContainer.Resolve{T}()"/> an instance of this <see cref="IRegistration.InterfaceType"/>
/// <para>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</para>
/// </summary>
/// <param name="parameters">The parameters with their position</param>
/// <returns>The current instance of this <see cref="IRegistrationBase{TInterface}"/></returns>
/// <exception cref="InvalidRegistrationException"><see cref="Parameters"/> are already set or no parameters given</exception>
public IRegistrationBase<TInterface> 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;
}
} }
} }
Loading…
Cancel
Save