#51: get a constructor resolve stack before actually resolving parameters

-> no unused parameters are generated while checking if a constructor can actually be used
pull/57/head
Simon G 4 years ago
parent b09eee2f6c
commit dd2e0fe4d7
  1. 13
      LightweightIocContainer/GenericMethodCaller.cs
  2. 249
      LightweightIocContainer/IocContainer.cs
  3. 31
      LightweightIocContainer/LightweightIocContainer.xml
  4. 1
      LightweightIocContainer/Registrations/RegistrationBase.cs
  5. 2
      LightweightIocContainer/ResolvePlaceholders/InternalResolvePlaceholder.cs
  6. 24
      LightweightIocContainer/ResolvePlaceholders/InternalToBeResolvedPlaceholder.cs
  7. 1
      Test.LightweightIocContainer/RegistrationBaseTest.cs

@ -41,5 +41,18 @@ namespace LightweightIocContainer
throw ex.GetBaseException(); throw ex.GetBaseException();
} }
} }
/// <summary>
/// Call a private generic method without generic type parameters
/// </summary>
/// <param name="caller">The caller of the method</param>
/// <param name="functionName">The name of the method to call</param>
/// <param name="genericParameter">The generic parameter as <see cref="Type"/> parameter</param>
/// <param name="parameters">The parameters of the method</param>
/// <returns>The result of invoking the method</returns>
/// <exception cref="GenericMethodNotFoundException">Could not find the generic method</exception>
/// <exception cref="Exception">Any <see cref="Exception"/> thrown after invoking the generic method</exception>
public static object CallPrivate(object caller, string functionName, Type genericParameter, params object[] parameters) =>
Call(caller, functionName, genericParameter, BindingFlags.NonPublic | BindingFlags.Instance, parameters);
} }
} }

@ -15,6 +15,7 @@ using LightweightIocContainer.Interfaces.Installers;
using LightweightIocContainer.Interfaces.Registrations; using LightweightIocContainer.Interfaces.Registrations;
using LightweightIocContainer.Interfaces.Registrations.Fluent; using LightweightIocContainer.Interfaces.Registrations.Fluent;
using LightweightIocContainer.Registrations; using LightweightIocContainer.Registrations;
using LightweightIocContainer.ResolvePlaceholders;
namespace LightweightIocContainer namespace LightweightIocContainer
{ {
@ -266,7 +267,24 @@ namespace LightweightIocContainer
/// <returns>An instance of the given <see cref="Type"/></returns> /// <returns>An instance of the given <see cref="Type"/></returns>
/// <exception cref="InternalResolveException">Could not find function <see cref="ResolveInternal{T}"/></exception> /// <exception cref="InternalResolveException">Could not find function <see cref="ResolveInternal{T}"/></exception>
internal object Resolve(Type type, object[] arguments, List<Type> resolveStack) => internal object Resolve(Type type, object[] arguments, List<Type> resolveStack) =>
GenericMethodCaller.Call(this, nameof(ResolveInternal), type, BindingFlags.NonPublic | BindingFlags.Instance, arguments, resolveStack); GenericMethodCaller.CallPrivate(this, nameof(ResolveInternal), type, arguments, resolveStack);
private object Resolve(InternalToBeResolvedPlaceholder toBeResolvedPlaceholder, List<Type> resolveStack)
{
if (toBeResolvedPlaceholder.Parameters == null)
return Resolve(toBeResolvedPlaceholder.ResolvedType, null, resolveStack);
List<object> parameters = new();
foreach (object parameter in toBeResolvedPlaceholder.Parameters)
{
if (parameter is InternalToBeResolvedPlaceholder internalToBeResolvedPlaceholder)
parameters.Add(Resolve(internalToBeResolvedPlaceholder, resolveStack));
else
parameters.Add(parameter);
}
return Resolve(toBeResolvedPlaceholder.ResolvedType, parameters.ToArray(), resolveStack);
}
/// <summary> /// <summary>
/// Gets an instance of a given registered <see cref="Type"/> /// Gets an instance of a given registered <see cref="Type"/>
@ -282,12 +300,7 @@ namespace LightweightIocContainer
IRegistration registration = FindRegistration<T>() ?? throw new TypeNotRegisteredException(typeof(T)); IRegistration registration = FindRegistration<T>() ?? throw new TypeNotRegisteredException(typeof(T));
//Circular dependency check //Circular dependency check
if (resolveStack == null) //first resolve call resolveStack = CheckForCircularDependencies<T>(resolveStack);
resolveStack = new List<Type> {typeof(T)}; //create new stack and add the currently resolving type to the stack
else if (resolveStack.Contains(typeof(T)))
throw new CircularDependencyException(typeof(T), resolveStack); //currently resolving type is still resolving -> circular dependency
else //not the first resolve call in chain but no circular dependencies for now
resolveStack.Add(typeof(T)); //add currently resolving type to the stack
T resolvedInstance = registration switch T resolvedInstance = registration switch
{ {
@ -313,15 +326,9 @@ namespace LightweightIocContainer
/// <returns>An existing or newly created singleton instance of the given <see cref="Type"/></returns> /// <returns>An existing or newly created singleton instance of the given <see cref="Type"/></returns>
private T GetOrCreateSingletonInstance<T>(IRegistration registration, object[] arguments, List<Type> resolveStack) private T GetOrCreateSingletonInstance<T>(IRegistration registration, object[] arguments, List<Type> resolveStack)
{ {
Type type = registration switch Type type = GetType<T>(registration);
{
ITypedRegistration typedRegistration => typedRegistration.ImplementationType,
ISingleTypeRegistration<T> singleTypeRegistration => singleTypeRegistration.InterfaceType,
_ => throw new UnknownRegistrationException($"There is no registration {registration.GetType().Name} that can have lifestyle singleton.")
};
//if a singleton instance exists return it object instance = TryGetSingletonInstance(type);
object instance = _singletons.FirstOrDefault(s => s.type == type).instance;
if (instance != null) if (instance != null)
return (T) instance; return (T) instance;
@ -332,6 +339,8 @@ namespace LightweightIocContainer
return newInstance; return newInstance;
} }
private object TryGetSingletonInstance(Type type) => _singletons.FirstOrDefault(s => s.type == type).instance; //if a singleton instance exists return it
/// <summary> /// <summary>
/// Gets or creates a multiton instance of a given <see cref="Type"/> /// Gets or creates a multiton instance of a given <see cref="Type"/>
/// </summary> /// </summary>
@ -390,7 +399,7 @@ namespace LightweightIocContainer
T instance; T instance;
if (registration is IOpenGenericRegistration openGenericRegistration) if (registration is IOpenGenericRegistration openGenericRegistration)
{ {
arguments = ResolveConstructorArguments(openGenericRegistration.ImplementationType, arguments, resolveStack); arguments = ResolveTypeCreationArguments(openGenericRegistration.ImplementationType, arguments, resolveStack);
//create generic implementation type from generic arguments of T //create generic implementation type from generic arguments of T
Type genericImplementationType = openGenericRegistration.ImplementationType.MakeGenericType(typeof(T).GenericTypeArguments); Type genericImplementationType = openGenericRegistration.ImplementationType.MakeGenericType(typeof(T).GenericTypeArguments);
@ -399,7 +408,7 @@ namespace LightweightIocContainer
} }
else if (registration is ITypedRegistration defaultRegistration) else if (registration is ITypedRegistration defaultRegistration)
{ {
arguments = ResolveConstructorArguments(defaultRegistration.ImplementationType, arguments, resolveStack); arguments = ResolveTypeCreationArguments(defaultRegistration.ImplementationType, arguments, resolveStack);
instance = (T) Activator.CreateInstance(defaultRegistration.ImplementationType, arguments); instance = (T) Activator.CreateInstance(defaultRegistration.ImplementationType, arguments);
} }
else if (registration is ISingleTypeRegistration<T> singleTypeRegistration) else if (registration is ISingleTypeRegistration<T> singleTypeRegistration)
@ -409,7 +418,7 @@ namespace LightweightIocContainer
if (singleTypeRegistration.FactoryMethod == null) //type registration without interface -> just create this type if (singleTypeRegistration.FactoryMethod == null) //type registration without interface -> just create this type
{ {
arguments = ResolveConstructorArguments(singleTypeRegistration.InterfaceType, arguments, resolveStack); arguments = ResolveTypeCreationArguments(singleTypeRegistration.InterfaceType, arguments, resolveStack);
instance = (T)Activator.CreateInstance(singleTypeRegistration.InterfaceType, arguments); instance = (T)Activator.CreateInstance(singleTypeRegistration.InterfaceType, arguments);
} }
else //factory method set to create the instance else //factory method set to create the instance
@ -468,7 +477,7 @@ namespace LightweightIocContainer
} }
/// <summary> /// <summary>
/// Resolve the missing constructor arguments /// Resolve the missing type creation arguments
/// </summary> /// </summary>
/// <param name="type">The <see cref="Type"/> that will be created</param> /// <param name="type">The <see cref="Type"/> that will be created</param>
/// <param name="arguments">The existing arguments</param> /// <param name="arguments">The existing arguments</param>
@ -476,99 +485,185 @@ namespace LightweightIocContainer
/// <returns>An array of all needed constructor arguments to create the <see cref="Type"/></returns> /// <returns>An array of all needed constructor arguments to create the <see cref="Type"/></returns>
/// <exception cref="NoMatchingConstructorFoundException">No matching constructor was found for the given or resolvable arguments</exception> /// <exception cref="NoMatchingConstructorFoundException">No matching constructor was found for the given or resolvable arguments</exception>
[CanBeNull] [CanBeNull]
private object[] ResolveConstructorArguments(Type type, object[] arguments, List<Type> resolveStack) private object[] ResolveTypeCreationArguments(Type type, object[] arguments, List<Type> resolveStack)
{ {
NoMatchingConstructorFoundException noMatchingConstructorFoundException = null;
//find best ctor //find best ctor
List<ConstructorInfo> sortedConstructors = type.GetConstructors().OrderByDescending(c => c.GetParameters().Length).ToList(); List<ConstructorInfo> sortedConstructors = TryGetSortedConstructors(type);
if (!sortedConstructors.Any()) //no public constructor available foreach (ConstructorInfo constructor in sortedConstructors)
throw new NoPublicConstructorFoundException(type); {
(bool result, List<object> parameters, List<ConstructorNotMatchingException> exceptions) = TryGetConstructorResolveStack(constructor, arguments, resolveStack);
NoMatchingConstructorFoundException noMatchingConstructorFoundException = null; if (result)
{
if (parameters == null)
return null;
foreach (ConstructorInfo ctor in sortedConstructors) List<object> constructorParameters = new();
foreach (object parameter in parameters)
{
if (parameter is InternalToBeResolvedPlaceholder toBeResolvedPlaceholder)
constructorParameters.Add(Resolve(toBeResolvedPlaceholder, resolveStack));
else
constructorParameters.Add(parameter);
}
return constructorParameters.ToArray();
}
noMatchingConstructorFoundException ??= new NoMatchingConstructorFoundException(type);
exceptions.ForEach(e =>
noMatchingConstructorFoundException.AddInnerException(new ConstructorNotMatchingException(constructor, e)));
}
if (noMatchingConstructorFoundException != null)
throw noMatchingConstructorFoundException;
return null;
}
private (bool result, List<object> parameters, List<ConstructorNotMatchingException> constructorNotMatchingExceptions) TryGetConstructorResolveStack(ConstructorInfo constructor, object[] arguments, List<Type> resolveStack)
{
List<ParameterInfo> constructorParameters = constructor.GetParameters().ToList();
if (!constructorParameters.Any())
return (true, null, null);
List<ConstructorNotMatchingException> constructorNotMatchingExceptions = new();
List<object> parameters = new();
List<object> passedArguments = null;
if (arguments != null)
passedArguments = new List<object>(arguments);
foreach (ParameterInfo parameter in constructorParameters)
{ {
try object fittingArgument = new InternalResolvePlaceholder();
if (passedArguments != null)
{ {
List<object> argumentsList = arguments?.ToList(); fittingArgument = passedArguments.FirstOrGiven<object, InternalResolvePlaceholder>(a =>
List<object> ctorParams = new(); a?.GetType() == parameter.ParameterType || parameter.ParameterType.IsInstanceOfType(a));
ParameterInfo[] parameters = ctor.GetParameters(); if (fittingArgument is not InternalResolvePlaceholder)
foreach (ParameterInfo parameter in parameters)
{ {
object fittingArgument = new InternalResolvePlaceholder(); int index = passedArguments.IndexOf(fittingArgument); //todo
if (argumentsList != null) passedArguments[index] = new InternalResolvePlaceholder();
}
}
if (fittingArgument is InternalResolvePlaceholder)
{
try
{
IRegistration registration = FindRegistration(parameter.ParameterType) ?? throw new TypeNotRegisteredException(parameter.ParameterType);
List<Type> internalResolveStack = new(resolveStack);
internalResolveStack = CheckForCircularDependencies(parameter.ParameterType, internalResolveStack); //testMe: seems to work
Type registeredType = GetTypeNonGeneric(parameter.ParameterType, registration);
object singletonInstance = TryGetSingletonInstance(registeredType);
if (singletonInstance != null)
fittingArgument = singletonInstance;
else
{ {
fittingArgument = argumentsList.FirstOrGiven<object, InternalResolvePlaceholder>(a => object[] argumentsForRegistration = null;
a?.GetType() == parameter.ParameterType || parameter.ParameterType.IsInstanceOfType(a)); if (registration is IWithParametersInternal { Parameters: { } } registrationWithParameters)
argumentsForRegistration = UpdateArgumentsWithRegistrationParameters(registrationWithParameters, null);
if (fittingArgument is not InternalResolvePlaceholder) foreach (ConstructorInfo registeredTypeConstructor in TryGetSortedConstructors(registeredType))
{
int index = argumentsList.IndexOf(fittingArgument);
argumentsList[index] = new InternalResolvePlaceholder();
}
else //fittingArgument is InternalResolvePlaceholder
{ {
try (bool result, List<object> parametersToResolve, List<ConstructorNotMatchingException> exceptions) =
TryGetConstructorResolveStack(registeredTypeConstructor, argumentsForRegistration, internalResolveStack);
if (result)
{ {
fittingArgument = Resolve(parameter.ParameterType, null, resolveStack); fittingArgument = new InternalToBeResolvedPlaceholder(registeredType, parametersToResolve);
break;
} }
catch (Exception)
{
fittingArgument = argumentsList.FirstOrGiven<object, InternalResolvePlaceholder>(a => parameter.ParameterType.GetDefault() == a);
if (fittingArgument is not InternalResolvePlaceholder) constructorNotMatchingExceptions.AddRange(exceptions);
{
int index = argumentsList.IndexOf(fittingArgument);
argumentsList[index] = new InternalResolvePlaceholder();
}
}
} }
} }
}
if (fittingArgument is InternalResolvePlaceholder && parameter.HasDefaultValue) catch (Exception exception)
ctorParams.Add(parameter.DefaultValue); {
else if (fittingArgument is InternalResolvePlaceholder) constructorNotMatchingExceptions.Add(new ConstructorNotMatchingException(constructor, exception));
ctorParams.Add(Resolve(parameter.ParameterType, null, resolveStack));
else
ctorParams.Add(fittingArgument);
} }
return ctorParams.ToArray(); if (fittingArgument is InternalResolvePlaceholder && passedArguments != null)
} {
catch (CircularDependencyException) //don't handle circular dependencies as no matching constructor, just rethrow them fittingArgument = passedArguments.FirstOrGiven<object, InternalResolvePlaceholder>(a => parameter.ParameterType.GetDefault() == a);
{
throw; if (fittingArgument is not InternalResolvePlaceholder)
} {
catch (Exception ex) int index = passedArguments.IndexOf(fittingArgument);
{ passedArguments[index] = new InternalResolvePlaceholder();
noMatchingConstructorFoundException ??= new NoMatchingConstructorFoundException(type); }
noMatchingConstructorFoundException.AddInnerException(new ConstructorNotMatchingException(ctor, ex)); }
} }
}
if (noMatchingConstructorFoundException != null) if (fittingArgument is InternalResolvePlaceholder && parameter.HasDefaultValue)
throw noMatchingConstructorFoundException; parameters.Add(parameter.DefaultValue);
else
parameters.Add(fittingArgument);
}
return null; return (!parameters.Any(p => p is InternalResolvePlaceholder), parameters, constructorNotMatchingExceptions);
} }
[CanBeNull] [CanBeNull]
private IRegistration FindRegistration<T>() private IRegistration FindRegistration<T>() => FindRegistration(typeof(T));
[CanBeNull]
private IRegistration FindRegistration(Type type)
{ {
IRegistration registration = Registrations.FirstOrDefault(r => r.InterfaceType == typeof(T)); IRegistration registration = Registrations.FirstOrDefault(r => r.InterfaceType == type);
if (registration != null) if (registration != null)
return registration; return registration;
registration = Registrations.OfType<ITypedRegistration>().FirstOrDefault(r => r.ImplementationType == typeof(T)); registration = Registrations.OfType<ITypedRegistration>().FirstOrDefault(r => r.ImplementationType == type);
if (registration != null) if (registration != null)
return registration; return registration;
//check for open generic registration //check for open generic registration
if (!typeof(T).GenericTypeArguments.Any()) if (!type.GenericTypeArguments.Any())
return null; return null;
List<IRegistration> openGenericRegistrations = Registrations.Where(r => r.InterfaceType.ContainsGenericParameters).ToList(); List<IRegistration> openGenericRegistrations = Registrations.Where(r => r.InterfaceType.ContainsGenericParameters).ToList();
return !openGenericRegistrations.Any() ? null : openGenericRegistrations.FirstOrDefault(r => r.InterfaceType == typeof(T).GetGenericTypeDefinition()); return !openGenericRegistrations.Any() ? null : openGenericRegistrations.FirstOrDefault(r => r.InterfaceType == type.GetGenericTypeDefinition());
}
private List<ConstructorInfo> TryGetSortedConstructors(Type type)
{
List<ConstructorInfo> sortedConstructors = type.GetConstructors().OrderByDescending(c => c.GetParameters().Length).ToList();
if (!sortedConstructors.Any()) //no public constructor available
throw new NoPublicConstructorFoundException(type);
return sortedConstructors;
}
private Type GetType<T>(IRegistration registration) =>
registration switch
{
ITypedRegistration typedRegistration => typedRegistration.ImplementationType,
ISingleTypeRegistration<T> singleTypeRegistration => singleTypeRegistration.InterfaceType,
_ => throw new UnknownRegistrationException($"Unknown registration used: {registration.GetType().Name}.")
};
private Type GetTypeNonGeneric(Type type, IRegistration registration) => (Type) GenericMethodCaller.CallPrivate(this, nameof(GetType), type, registration);
private List<Type> CheckForCircularDependencies<T>(List<Type> resolveStack) => CheckForCircularDependencies(typeof(T), resolveStack);
private List<Type> CheckForCircularDependencies(Type type, List<Type> resolveStack)
{
if (resolveStack == null) //first resolve call
resolveStack = new List<Type> {type}; //create new stack and add the currently resolving type to the stack
else if (resolveStack.Contains(type))
throw new CircularDependencyException(type, resolveStack); //currently resolving type is still resolving -> circular dependency
else //not the first resolve call in chain but no circular dependencies for now
resolveStack.Add(type); //add currently resolving type to the stack
return resolveStack;
} }
/// <summary> /// <summary>

@ -331,6 +331,18 @@
<exception cref="T:LightweightIocContainer.Exceptions.GenericMethodNotFoundException">Could not find the generic method</exception> <exception cref="T:LightweightIocContainer.Exceptions.GenericMethodNotFoundException">Could not find the generic method</exception>
<exception cref="T:System.Exception">Any <see cref="T:System.Exception"/> thrown after invoking the generic method</exception> <exception cref="T:System.Exception">Any <see cref="T:System.Exception"/> thrown after invoking the generic method</exception>
</member> </member>
<member name="M:LightweightIocContainer.GenericMethodCaller.CallPrivate(System.Object,System.String,System.Type,System.Object[])">
<summary>
Call a private generic method without generic type parameters
</summary>
<param name="caller">The caller of the method</param>
<param name="functionName">The name of the method to call</param>
<param name="genericParameter">The generic parameter as <see cref="T:System.Type"/> parameter</param>
<param name="parameters">The parameters of the method</param>
<returns>The result of invoking the method</returns>
<exception cref="T:LightweightIocContainer.Exceptions.GenericMethodNotFoundException">Could not find the generic method</exception>
<exception cref="T:System.Exception">Any <see cref="T:System.Exception"/> thrown after invoking the generic method</exception>
</member>
<member name="T:LightweightIocContainer.Installers.AssemblyInstaller"> <member name="T:LightweightIocContainer.Installers.AssemblyInstaller">
<summary> <summary>
An <see cref="T:LightweightIocContainer.Interfaces.Installers.IIocInstaller"/> that installs all <see cref="T:LightweightIocContainer.Interfaces.Installers.IIocInstaller"/>s for its given <see cref="T:System.Reflection.Assembly"/> An <see cref="T:LightweightIocContainer.Interfaces.Installers.IIocInstaller"/> that installs all <see cref="T:LightweightIocContainer.Interfaces.Installers.IIocInstaller"/>s for its given <see cref="T:System.Reflection.Assembly"/>
@ -777,11 +789,6 @@
A <see cref="T:LightweightIocContainer.Interfaces.Registrations.IRegistration"/> that implements a <see cref="T:System.Type"/> A <see cref="T:LightweightIocContainer.Interfaces.Registrations.IRegistration"/> that implements a <see cref="T:System.Type"/>
</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
@ -990,9 +997,9 @@
<param name="arguments">The constructor arguments</param> <param name="arguments">The constructor arguments</param>
<returns>The argument list updated with the <see cref="P:LightweightIocContainer.Interfaces.Registrations.Fluent.IWithParametersInternal.Parameters"/></returns> <returns>The argument list updated with the <see cref="P:LightweightIocContainer.Interfaces.Registrations.Fluent.IWithParametersInternal.Parameters"/></returns>
</member> </member>
<member name="M:LightweightIocContainer.IocContainer.ResolveConstructorArguments(System.Type,System.Object[],System.Collections.Generic.List{System.Type})"> <member name="M:LightweightIocContainer.IocContainer.ResolveTypeCreationArguments(System.Type,System.Object[],System.Collections.Generic.List{System.Type})">
<summary> <summary>
Resolve the missing constructor arguments Resolve the missing type creation arguments
</summary> </summary>
<param name="type">The <see cref="T:System.Type"/> that will be created</param> <param name="type">The <see cref="T:System.Type"/> that will be created</param>
<param name="arguments">The existing arguments</param> <param name="arguments">The existing arguments</param>
@ -1497,6 +1504,16 @@
<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.ITypedRegistration`2"/></returns> <returns>The current instance of this <see cref="T:LightweightIocContainer.Interfaces.Registrations.ITypedRegistration`2"/></returns>
</member> </member>
<member name="T:LightweightIocContainer.ResolvePlaceholders.InternalResolvePlaceholder">
<summary>
An internal placeholder that is used during the resolving process
</summary>
</member>
<member name="T:LightweightIocContainer.ResolvePlaceholders.InternalToBeResolvedPlaceholder">
<summary>
An internal placeholder that is used to hold types that need to be resolved during the resolving process
</summary>
</member>
<member name="M:LightweightIocContainer.TypeExtension.GetDefault(System.Type)"> <member name="M:LightweightIocContainer.TypeExtension.GetDefault(System.Type)">
<summary> <summary>
Returns the default value for a given <see cref="T:System.Type"/> Returns the default value for a given <see cref="T:System.Type"/>

@ -10,6 +10,7 @@ using LightweightIocContainer.Interfaces.Factories;
using LightweightIocContainer.Interfaces.Installers; using LightweightIocContainer.Interfaces.Installers;
using LightweightIocContainer.Interfaces.Registrations; using LightweightIocContainer.Interfaces.Registrations;
using LightweightIocContainer.Interfaces.Registrations.Fluent; using LightweightIocContainer.Interfaces.Registrations.Fluent;
using LightweightIocContainer.ResolvePlaceholders;
namespace LightweightIocContainer.Registrations namespace LightweightIocContainer.Registrations
{ {

@ -2,7 +2,7 @@
// Created: 2019-11-22 // Created: 2019-11-22
// Copyright(c) 2019 SimonG. All Rights Reserved. // Copyright(c) 2019 SimonG. All Rights Reserved.
namespace LightweightIocContainer namespace LightweightIocContainer.ResolvePlaceholders
{ {
/// <summary> /// <summary>
/// An internal placeholder that is used during the resolving process /// An internal placeholder that is used during the resolving process

@ -0,0 +1,24 @@
// Author: Gockner, Simon
// Created: 2021-12-08
// Copyright(c) 2021 SimonG. All Rights Reserved.
using System;
using System.Collections.Generic;
namespace LightweightIocContainer.ResolvePlaceholders
{
/// <summary>
/// An internal placeholder that is used to hold types that need to be resolved during the resolving process
/// </summary>
internal class InternalToBeResolvedPlaceholder
{
public InternalToBeResolvedPlaceholder(Type resolvedType, List<object> parameters)
{
ResolvedType = resolvedType;
Parameters = parameters;
}
public Type ResolvedType { get; }
public List<object> Parameters { get; }
}
}

@ -6,6 +6,7 @@ using JetBrains.Annotations;
using LightweightIocContainer; using LightweightIocContainer;
using LightweightIocContainer.Exceptions; using LightweightIocContainer.Exceptions;
using LightweightIocContainer.Registrations; using LightweightIocContainer.Registrations;
using LightweightIocContainer.ResolvePlaceholders;
using Moq; using Moq;
using NUnit.Framework; using NUnit.Framework;

Loading…
Cancel
Save