diff --git a/LightweightIocContainer/Creator.cs b/LightweightIocContainer/Creator.cs
new file mode 100644
index 0000000..89daa6c
--- /dev/null
+++ b/LightweightIocContainer/Creator.cs
@@ -0,0 +1,24 @@
+// Author: Gockner, Simon
+// Created: 2021-12-14
+// Copyright(c) 2021 SimonG. All Rights Reserved.
+
+using System;
+
+namespace LightweightIocContainer;
+
+///
+/// Helper for dynamic instance creation
+///
+internal static class Creator
+{
+ ///
+ /// Creates an instance of the given with the given arguments
+ ///
+ /// The given
+ /// The given arguments
+ /// The that is returned
+ /// A new instance of the given
+ /// The given type could not be created
+ public static T CreateInstance(Type type, params object?[]? arguments) =>
+ (T) (Activator.CreateInstance(type, arguments) ?? throw new InvalidOperationException($"Type {type} could not be created."));
+}
\ No newline at end of file
diff --git a/LightweightIocContainer/Factories/TypedFactory.cs b/LightweightIocContainer/Factories/TypedFactory.cs
index 88df1dd..e4f4e0b 100644
--- a/LightweightIocContainer/Factories/TypedFactory.cs
+++ b/LightweightIocContainer/Factories/TypedFactory.cs
@@ -92,11 +92,11 @@ namespace LightweightIocContainer.Factories
}
else
{
- MethodInfo? emptyArray = typeof(Array).GetMethod(nameof(Array.Empty))?.MakeGenericMethod(typeof(object));
+ MethodInfo emptyArray = typeof(Array).GetMethod(nameof(Array.Empty))!.MakeGenericMethod(typeof(object));
generator.EmitCall(OpCodes.Call, emptyArray, null);
}
- generator.EmitCall(OpCodes.Callvirt, typeof(IResolver).GetMethod(nameof(IResolver.Resolve), new[] { typeof(object[]) })?.MakeGenericMethod(createMethod.ReturnType), null);
+ generator.EmitCall(OpCodes.Callvirt, typeof(IResolver).GetMethod(nameof(IResolver.Resolve), new[] { typeof(object[]) })!.MakeGenericMethod(createMethod.ReturnType), null);
generator.Emit(OpCodes.Castclass, createMethod.ReturnType);
generator.Emit(OpCodes.Ret);
}
@@ -127,7 +127,7 @@ namespace LightweightIocContainer.Factories
multitonClearGenerator.Emit(OpCodes.Ldarg_0);
multitonClearGenerator.Emit(OpCodes.Ldfld, containerFieldBuilder);
- multitonClearGenerator.EmitCall(OpCodes.Callvirt, typeof(IIocContainer).GetMethod(nameof(IIocContainer.ClearMultitonInstances))?.MakeGenericMethod(typeToClear), null);
+ multitonClearGenerator.EmitCall(OpCodes.Callvirt, typeof(IIocContainer).GetMethod(nameof(IIocContainer.ClearMultitonInstances))!.MakeGenericMethod(typeToClear), null);
multitonClearGenerator.Emit(OpCodes.Ret);
}
else
@@ -136,7 +136,7 @@ namespace LightweightIocContainer.Factories
}
}
- return (TFactory) Activator.CreateInstance(typeBuilder.CreateTypeInfo()?.AsType(), container);
+ return Creator.CreateInstance(typeBuilder.CreateTypeInfo()!.AsType(), container);
}
}
}
\ No newline at end of file
diff --git a/LightweightIocContainer/GenericMethodCaller.cs b/LightweightIocContainer/GenericMethodCaller.cs
index 8052c37..41c1da2 100644
--- a/LightweightIocContainer/GenericMethodCaller.cs
+++ b/LightweightIocContainer/GenericMethodCaller.cs
@@ -24,7 +24,7 @@ namespace LightweightIocContainer
/// The result of invoking the method
/// Could not find the generic method
/// Any thrown after invoking the generic method
- public static object Call(object caller, string functionName, Type genericParameter, BindingFlags bindingFlags, params object?[] parameters)
+ public static object? Call(object caller, string functionName, Type genericParameter, BindingFlags bindingFlags, params object?[] parameters)
{
MethodInfo? method = caller.GetType().GetMethod(functionName, bindingFlags);
MethodInfo? genericMethod = method?.MakeGenericMethod(genericParameter);
@@ -52,7 +52,7 @@ namespace LightweightIocContainer
/// The result of invoking the method
/// Could not find the generic method
/// Any thrown after invoking the generic method
- public static object CallPrivate(object caller, string functionName, Type genericParameter, params object?[] parameters) =>
+ public static object? CallPrivate(object caller, string functionName, Type genericParameter, params object?[] parameters) =>
Call(caller, functionName, genericParameter, BindingFlags.NonPublic | BindingFlags.Instance, parameters);
}
}
\ No newline at end of file
diff --git a/LightweightIocContainer/Installers/AssemblyInstaller.cs b/LightweightIocContainer/Installers/AssemblyInstaller.cs
index af63a20..9fc8c0d 100644
--- a/LightweightIocContainer/Installers/AssemblyInstaller.cs
+++ b/LightweightIocContainer/Installers/AssemblyInstaller.cs
@@ -29,7 +29,7 @@ namespace LightweightIocContainer.Installers
if (!typeof(IIocInstaller).IsAssignableFrom(type) || type.IsNestedPrivate)
continue;
- Installers.Add((IIocInstaller) Activator.CreateInstance(type));
+ Installers.Add(Creator.CreateInstance(type));
}
}
diff --git a/LightweightIocContainer/IocContainer.cs b/LightweightIocContainer/IocContainer.cs
index 881d037..5af49ed 100644
--- a/LightweightIocContainer/IocContainer.cs
+++ b/LightweightIocContainer/IocContainer.cs
@@ -270,182 +270,271 @@ namespace LightweightIocContainer
/// The current resolve stack
/// An instance of the given
/// Could not find function
- internal object Resolve(Type type, object?[]? arguments, List? resolveStack) =>
+ internal object? Resolve(Type type, object?[]? arguments, List? resolveStack) =>
GenericMethodCaller.CallPrivate(this, nameof(ResolveInternal), type, arguments, resolveStack);
+ ///
+ /// Gets an instance of a given registered
+ ///
+ /// The registered
+ /// The constructor arguments
+ /// The current resolve stack
+ /// An instance of the given registered
+ private T ResolveInternal(object[]? arguments, List? resolveStack = null) => ResolveInstance(TryResolve(arguments, resolveStack));
+
+ ///
+ /// Tries to resolve the given with the given arguments
+ ///
+ /// The given arguments
+ /// The current resolve stack
+ /// The registered
+ /// An instance of the given registered , an if parameters need to be resolved or an if a factory method is used to create an instance
+ /// The given is not registered
+ /// An interface was registered without an implementation or factory method
+ /// Tried resolving a multiton without scope argument
+ /// No matching constructor for the given found
+ /// Getting resolve stack failed without exception
+ private object TryResolve(object[]? arguments, List? resolveStack)
+ {
+ IRegistration registration = FindRegistration() ?? throw new TypeNotRegisteredException(typeof(T));
+
+ List internalResolveStack = resolveStack == null ? new List() : new List(resolveStack);
+ internalResolveStack = CheckForCircularDependencies(internalResolveStack);
+
+ object? existingInstance = TryGetExistingInstance(registration, arguments);
+ if (existingInstance != null)
+ return existingInstance;
+
+ 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)
+ return new InternalFactoryMethodPlaceholder(singleTypeRegistration);
+ }
+
+ if (registration is IWithParametersInternal { Parameters: { } } registrationWithParameters)
+ arguments = UpdateArgumentsWithRegistrationParameters(registrationWithParameters, arguments);
+
+ Type registeredType = GetType(registration);
+ (bool result, List? parametersToResolve, NoMatchingConstructorFoundException? exception) =
+ TryGetTypeResolveStack(registeredType, arguments, internalResolveStack);
+
+ if (registration is IMultitonRegistration multitonRegistration)
+ {
+ if (arguments == null || !arguments.Any())
+ throw new MultitonResolveException("Can not resolve multiton without arguments.", registration.InterfaceType);
+
+ object multitonScopeArgument = TryGetMultitonScopeArgument(multitonRegistration, arguments);
+
+ parametersToResolve ??= new List();
+ parametersToResolve.Add(multitonScopeArgument);
+ }
+
+ if (result)
+ return new InternalToBeResolvedPlaceholder(registeredType, registration, parametersToResolve);
+
+ if (exception != null)
+ throw exception;
+
+ throw new InternalResolveException("Getting resolve stack failed without exception.");
+ }
+
+ ///
+ /// Tries to resolve the given with the given arguments without generic arguments
+ ///
+ /// The registered
+ /// The given arguments
+ /// The current resolve stack
+ /// An instance of the given registered , an if parameters need to be resolved or an if a factory method is used to create an instance
+ /// The given is not registered
+ /// An interface was registered without an implementation or factory method
+ /// Tried resolving a multiton without scope argument
+ /// No matching constructor for the given found
+ /// Getting resolve stack failed without exception
+ private object? TryResolveNonGeneric(Type type, object[]? arguments, List resolveStack) =>
+ GenericMethodCaller.CallPrivate(this, nameof(TryResolve), type, arguments, resolveStack);
+
///
/// Recursively resolve a with the given parameters for an
///
/// The that includes the type and resolve stack
- /// The current resolve stack
/// A recursively resolved instance of the given
- private object Resolve(InternalToBeResolvedPlaceholder toBeResolvedPlaceholder, List resolveStack)
+ private T ResolvePlaceholder(InternalToBeResolvedPlaceholder toBeResolvedPlaceholder)
{
if (toBeResolvedPlaceholder.Parameters == null)
- return Resolve(toBeResolvedPlaceholder.ResolvedType, null, resolveStack);
+ return CreateInstance(toBeResolvedPlaceholder.ResolvedRegistration, null);
- List parameters = new();
- foreach (object parameter in toBeResolvedPlaceholder.Parameters)
+ List parameters = new();
+ foreach (object? parameter in toBeResolvedPlaceholder.Parameters)
{
- if (parameter is InternalToBeResolvedPlaceholder internalToBeResolvedPlaceholder)
- parameters.Add(Resolve(internalToBeResolvedPlaceholder, resolveStack));
+ if (parameter != null)
+ {
+ Type type = parameter is IInternalToBeResolvedPlaceholder internalToBeResolvedPlaceholder ?
+ internalToBeResolvedPlaceholder.ResolvedType : parameter.GetType();
+
+ parameters.Add(ResolveInstanceNonGeneric(type, parameter));
+ }
else
parameters.Add(parameter);
}
- return Resolve(toBeResolvedPlaceholder.ResolvedType, parameters.ToArray(), resolveStack);
+ return CreateInstance(toBeResolvedPlaceholder.ResolvedRegistration, parameters.ToArray());
}
-
+
///
- /// Gets an instance of a given registered
+ /// Resolve the given object instance
///
- /// The registered
- /// The constructor arguments
- /// The current resolve stack
- /// An instance of the given registered
- /// The given is not registered in this
- /// The registration for the given has an unknown
- private T ResolveInternal(object[]? arguments, List? resolveStack = null)
- {
- IRegistration registration = FindRegistration() ?? throw new TypeNotRegisteredException(typeof(T));
-
- //Circular dependency check
- resolveStack = CheckForCircularDependencies(resolveStack);
-
- T resolvedInstance = registration switch
+ /// The given resolved object
+ /// The of the returned instance
+ /// An instance of the given resolved object
+ /// Resolve returned wrong type
+ private T ResolveInstance(object resolvedObject) =>
+ resolvedObject switch
{
- RegistrationBase { Lifestyle: Lifestyle.Singleton } defaultRegistration => GetOrCreateSingletonInstance(defaultRegistration, arguments, resolveStack),
- RegistrationBase { Lifestyle: Lifestyle.Multiton } and IMultitonRegistration multitonRegistration => GetOrCreateMultitonInstance(multitonRegistration, arguments, resolveStack),
- RegistrationBase defaultRegistration => CreateInstance(defaultRegistration, arguments, resolveStack),
- ITypedFactoryRegistration typedFactoryRegistration => typedFactoryRegistration.Factory.Factory,
- _ => throw new UnknownRegistrationException($"There is no registration of type {registration.GetType().Name}.")
+ T instance => instance,
+ InternalToBeResolvedPlaceholder toBeResolvedPlaceholder => ResolvePlaceholder(toBeResolvedPlaceholder),
+ InternalFactoryMethodPlaceholder factoryMethodPlaceholder => factoryMethodPlaceholder.FactoryMethod(this),
+ _ => throw new InternalResolveException("Resolve returned wrong type.")
};
- resolveStack.Remove(typeof(T)); //T was successfully resolved -> no circular dependency -> remove from resolve stack
-
- return resolvedInstance;
- }
+ ///
+ /// Resolve the given object instance without generic arguments
+ ///
+ /// The of the returned instance
+ ///
+ /// An instance of the given resolved object
+ /// Resolve returned wrong type
+ private object? ResolveInstanceNonGeneric(Type type, object resolveObject) =>
+ GenericMethodCaller.CallPrivate(this, nameof(ResolveInstance), type, resolveObject);
///
- /// Gets or creates a singleton instance of a given
+ /// Creates an instance of a given
///
/// The given
/// The registration of the given
- /// The arguments to resolve
- /// The current resolve stack
- /// An existing or newly created singleton instance of the given
- private T GetOrCreateSingletonInstance(IRegistration registration, object[]? arguments, List resolveStack)
+ /// The constructor arguments
+ /// A newly created instance of the given
+ private T CreateInstance(IRegistration registration, object?[]? arguments)
{
- Type type = GetType(registration);
-
- object? instance = TryGetSingletonInstance(type);
- if (instance != null)
- return (T) instance;
+ T instance;
+ if (registration is IOpenGenericRegistration openGenericRegistration)
+ {
+ //create generic implementation type from generic arguments of T
+ Type genericImplementationType = openGenericRegistration.ImplementationType.MakeGenericType(typeof(T).GenericTypeArguments);
+ instance = Creator.CreateInstance(genericImplementationType, arguments);
+ }
+ else if (registration is ISingleTypeRegistration singleTypeRegistration)
+ instance = singleTypeRegistration.FactoryMethod == null ? Creator.CreateInstance(singleTypeRegistration.InterfaceType, arguments) : singleTypeRegistration.FactoryMethod(this);
+ else if (registration is ILifestyleProvider { Lifestyle: Lifestyle.Multiton } and IMultitonRegistration multitonRegistration)
+ instance = CreateMultitonInstance(multitonRegistration, arguments);
+ else if (registration is ITypedRegistration defaultRegistration)
+ instance = Creator.CreateInstance(defaultRegistration.ImplementationType, arguments);
+ else
+ throw new UnknownRegistrationException($"There is no registration of type {registration.GetType().Name}.");
- //if it doesn't already exist create a new instance and add it to the list
- T newInstance = CreateInstance(registration, arguments, resolveStack);
- _singletons.Add((type, newInstance));
+ if (registration is ILifestyleProvider { Lifestyle: Lifestyle.Singleton })
+ _singletons.Add((GetType(registration), instance));
- return newInstance;
+ if (registration is IOnCreate onCreateRegistration)
+ onCreateRegistration.OnCreateAction?.Invoke(instance); //TODO: Allow async OnCreateAction?
+
+ return instance;
}
///
- /// Try to get an existing singleton instance for a given
+ /// Try to get an already existing instance (factory, singleton, multiton)
///
- /// The given
- /// A singleton instance if existing for the given , null if not
- private object? TryGetSingletonInstance(Type type) => _singletons.FirstOrDefault(s => s.type == type).instance; //if a singleton instance exists return it
+ /// The given
+ /// The given arguments
+ /// The of the instance
+ /// An already existing instance if possible, null if not
+ private object? TryGetExistingInstance(IRegistration registration, IReadOnlyList? arguments) =>
+ registration switch
+ {
+ ITypedFactoryRegistration typedFactoryRegistration => typedFactoryRegistration.Factory.Factory,
+ ILifestyleProvider { Lifestyle: Lifestyle.Singleton } => TryGetSingletonInstance(registration),
+ ILifestyleProvider { Lifestyle: Lifestyle.Multiton } and IMultitonRegistration multitonRegistration => TryGetMultitonInstance(multitonRegistration, arguments),
+ _ => null
+ };
+
+ ///
+ /// Try to get an existing singleton instance for a given
+ ///
+ /// The
+ /// A singleton instance if existing for the given , null if not
+ private object? TryGetSingletonInstance(IRegistration registration) =>
+ _singletons.FirstOrDefault(s => s.type == GetType(registration)).instance; //if a singleton instance exists return it
///
- /// Gets or creates a multiton instance of a given
+ /// Try to get an existing multiton instance for a given
///
- /// The given
- /// The registration of the given
- /// The arguments to resolve
- /// The current resolve stack
- /// An existing or newly created multiton instance of the given
- /// No arguments given
- /// Scope argument not given
- private T GetOrCreateMultitonInstance(IMultitonRegistration registration, object[]? arguments, List resolveStack)
+ /// The given
+ /// The given arguments
+ /// A multiton instance if existing for the given , null if not
+ /// Tried resolving a multiton without scope argument
+ private object? TryGetMultitonInstance(IMultitonRegistration registration, IReadOnlyList? arguments)
{
if (arguments == null || !arguments.Any())
- throw new MultitonResolveException("Can not resolve multiton without arguments.", typeof(T));
-
- object scopeArgument = arguments[0];
- if (scopeArgument.GetType() != registration.Scope && !registration.Scope.IsInstanceOfType(scopeArgument))
- throw new MultitonResolveException($"Can not resolve multiton without the first argument being the scope (should be of type {registration.Scope}).", typeof(T));
+ throw new MultitonResolveException("Can not resolve multiton without arguments.", registration.InterfaceType);
+
+ object scopeArgument = TryGetMultitonScopeArgument(registration, arguments);
//if a multiton for the given scope exists return it
- var instances = _multitons.FirstOrDefault(m => m.type == registration.ImplementationType && m.scope == registration.Scope).instances; //get instances for the given type and scope (use implementation type to resolve the correct instance for multiple multiton registrations as well)
- if (instances != null)
- {
- if (instances.TryGetValue(scopeArgument, out object? instance) && instance != null)
- return (T) instance;
-
- T createdInstance = CreateInstance(registration, arguments, resolveStack);
- instances.Add(scopeArgument, createdInstance);
-
- return createdInstance;
- }
+ var matchingMultitons = _multitons.FirstOrDefault(m => m.type == registration.ImplementationType && m.scope == registration.Scope); //get instances for the given type and scope (use implementation type to resolve the correct instance for multiple multiton registrations as well)
+ if (matchingMultitons == default)
+ return null;
- T newInstance = CreateInstance(registration, arguments, resolveStack);
+ return matchingMultitons.instances.TryGetValue(scopeArgument, out object? instance) && instance != null ? instance : null;
+ }
- ConditionalWeakTable weakTable = new();
- weakTable.Add(scopeArgument, newInstance);
+ ///
+ /// Try to get the multiton scope argument for a given
+ ///
+ /// The given
+ /// The given arguments
+ /// The multiton scope argument for the given
+ /// Tried resolving a multiton without correct scope argument
+ private object TryGetMultitonScopeArgument(IMultitonRegistration registration, IReadOnlyList arguments)
+ {
+ object? scopeArgument = arguments[0];
+ if (scopeArgument?.GetType() != registration.Scope && !registration.Scope.IsInstanceOfType(scopeArgument))
+ throw new MultitonResolveException($"Can not resolve multiton without the first argument being the scope (should be of type {registration.Scope}).", registration.InterfaceType);
- _multitons.Add((registration.ImplementationType, registration.Scope, weakTable));
-
- return newInstance;
+ return scopeArgument;
}
-
+
///
- /// Creates an instance of a given
+ /// Gets or creates a multiton instance of a given
///
/// The given
/// The registration of the given
- /// The constructor arguments
- /// The current resolve stack
- /// A newly created instance of the given
- private T CreateInstance(IRegistration registration, object[]? arguments, List resolveStack)
+ /// The arguments to resolve
+ /// An existing or newly created multiton instance of the given
+ /// No arguments given
+ /// Scope argument not given
+ private T CreateMultitonInstance(IMultitonRegistration registration, object?[]? arguments)
{
- if (registration is IWithParametersInternal { Parameters: { } } registrationWithParameters)
- arguments = UpdateArgumentsWithRegistrationParameters(registrationWithParameters, arguments);
+ if (arguments == null || !arguments.Any())
+ throw new MultitonResolveException("Can not resolve multiton without arguments.", registration.InterfaceType);
+
+ object scopeArgument = TryGetMultitonScopeArgument(registration, arguments);
- T instance;
- if (registration is IOpenGenericRegistration openGenericRegistration)
+ //if a multiton for the given scope exists return it
+ var matchingMultitons = _multitons.FirstOrDefault(m => m.type == registration.ImplementationType && m.scope == registration.Scope); //get instances for the given type and scope (use implementation type to resolve the correct instance for multiple multiton registrations as well)
+ if (matchingMultitons != default)
{
- arguments = ResolveTypeCreationArguments(openGenericRegistration.ImplementationType, arguments, resolveStack);
-
- //create generic implementation type from generic arguments of T
- Type genericImplementationType = openGenericRegistration.ImplementationType.MakeGenericType(typeof(T).GenericTypeArguments);
+ T createdInstance = Creator.CreateInstance(registration.ImplementationType, arguments[1..]);
+ matchingMultitons.instances.Add(scopeArgument, createdInstance);
- instance = (T) Activator.CreateInstance(genericImplementationType, arguments);
- }
- else if (registration is ITypedRegistration defaultRegistration)
- {
- arguments = ResolveTypeCreationArguments(defaultRegistration.ImplementationType, arguments, resolveStack);
- instance = (T) Activator.CreateInstance(defaultRegistration.ImplementationType, arguments);
+ return createdInstance;
}
- 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 = ResolveTypeCreationArguments(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}.");
-
- if (registration is IOnCreate onCreateRegistration)
- onCreateRegistration.OnCreateAction?.Invoke(instance); //TODO: Allow async OnCreateAction?
+ T newInstance = Creator.CreateInstance(registration.ImplementationType, arguments[1..]);
+ _multitons.Add((registration.ImplementationType, registration.Scope, new ConditionalWeakTable { { scopeArgument, newInstance } }));
- return instance;
+ return newInstance;
}
///
@@ -494,41 +583,6 @@ namespace LightweightIocContainer
return arguments;
}
- ///
- /// Resolve the missing type creation arguments
- ///
- /// The that will be created
- /// The existing arguments
- /// The current resolve stack
- /// An array of all needed constructor arguments to create the
- /// No matching constructor was found for the given or resolvable arguments
- private object[]? ResolveTypeCreationArguments(Type type, object[]? arguments, List resolveStack)
- {
- (bool result, List? parameters, NoMatchingConstructorFoundException? exception) = TryGetTypeResolveStack(type, arguments, resolveStack);
-
- if (result)
- {
- if (parameters == null)
- return null;
-
- List constructorParameters = new();
- foreach (object parameter in parameters)
- {
- if (parameter is InternalToBeResolvedPlaceholder toBeResolvedPlaceholder)
- constructorParameters.Add(Resolve(toBeResolvedPlaceholder, resolveStack));
- else
- constructorParameters.Add(parameter);
- }
-
- return constructorParameters.ToArray();
- }
-
- if (exception != null)
- throw exception;
-
- return null;
- }
-
///
/// Try to get the resolve stack for a given
///
@@ -540,7 +594,7 @@ namespace LightweightIocContainer
/// parameters: The parameters needed to resolve the given
/// exception: A if no matching constructor was found
///
- private (bool result, List? parameters, NoMatchingConstructorFoundException? exception) TryGetTypeResolveStack(Type type, object[]? arguments, List resolveStack)
+ private (bool result, List? parameters, NoMatchingConstructorFoundException? exception) TryGetTypeResolveStack(Type type, object[]? arguments, List resolveStack)
{
NoMatchingConstructorFoundException? noMatchingConstructorFoundException = null;
@@ -548,7 +602,7 @@ namespace LightweightIocContainer
List sortedConstructors = TryGetSortedConstructors(type);
foreach (ConstructorInfo constructor in sortedConstructors)
{
- (bool result, List? parameters, List? exceptions) = TryGetConstructorResolveStack(constructor, arguments, resolveStack);
+ (bool result, List? parameters, List? exceptions) = TryGetConstructorResolveStack(constructor, arguments, resolveStack);
if (result)
return (true, parameters, null);
@@ -572,14 +626,14 @@ namespace LightweightIocContainer
/// parameters: The parameters needed to resolve the given
/// exception: A List of s if the constructor is not matching
///
- private (bool result, List? parameters, List? exceptions) TryGetConstructorResolveStack(ConstructorInfo constructor, object[]? arguments, List resolveStack)
+ private (bool result, List? parameters, List? exceptions) TryGetConstructorResolveStack(ConstructorInfo constructor, object[]? arguments, List resolveStack)
{
List constructorParameters = constructor.GetParameters().ToList();
if (!constructorParameters.Any())
return (true, null, null);
List exceptions = new();
- List parameters = new();
+ List parameters = new();
List? passedArguments = null;
if (arguments != null)
@@ -587,11 +641,11 @@ namespace LightweightIocContainer
foreach (ParameterInfo parameter in constructorParameters)
{
- object fittingArgument = new InternalResolvePlaceholder();
+ object? fittingArgument = new InternalResolvePlaceholder();
if (passedArguments != null)
{
fittingArgument = passedArguments.FirstOrGiven(a =>
- a?.GetType() == parameter.ParameterType || parameter.ParameterType.IsInstanceOfType(a));
+ a.GetType() == parameter.ParameterType || parameter.ParameterType.IsInstanceOfType(a));
if (fittingArgument is not InternalResolvePlaceholder)
passedArguments.Remove(fittingArgument);
@@ -601,30 +655,7 @@ namespace LightweightIocContainer
{
try
{
- IRegistration registration = FindRegistration(parameter.ParameterType) ?? throw new TypeNotRegisteredException(parameter.ParameterType);
-
- List internalResolveStack = new(resolveStack);
- internalResolveStack = CheckForCircularDependencies(parameter.ParameterType, internalResolveStack);
-
- Type registeredType = GetTypeNonGeneric(parameter.ParameterType, registration);
-
- object? singletonInstance = TryGetSingletonInstance(registeredType);
- if (singletonInstance != null)
- fittingArgument = singletonInstance;
- else
- {
- object[]? argumentsForRegistration = null;
- if (registration is IWithParametersInternal { Parameters: { } } registrationWithParameters)
- argumentsForRegistration = UpdateArgumentsWithRegistrationParameters(registrationWithParameters, null);
-
- (bool result, List? parametersToResolve, NoMatchingConstructorFoundException? exception) =
- TryGetTypeResolveStack(registeredType, argumentsForRegistration, internalResolveStack);
-
- if (result)
- fittingArgument = new InternalToBeResolvedPlaceholder(registeredType, parametersToResolve);
- else if (exception != null)
- exceptions.Add(new ConstructorNotMatchingException(constructor, exception));
- }
+ fittingArgument = TryResolveNonGeneric(parameter.ParameterType, null, resolveStack);
}
catch (Exception exception)
{
@@ -654,15 +685,9 @@ namespace LightweightIocContainer
///
/// The given
/// The for the given
- private IRegistration? FindRegistration() => FindRegistration(typeof(T));
-
- ///
- /// Find the for the given
- ///
- /// The given
- /// The for the given
- private IRegistration? FindRegistration(Type type)
+ private IRegistration? FindRegistration()
{
+ Type type = typeof(T);
IRegistration? registration = Registrations.FirstOrDefault(r => r.InterfaceType == type);
if (registration != null)
return registration;
@@ -709,15 +734,6 @@ namespace LightweightIocContainer
_ => throw new UnknownRegistrationException($"Unknown registration used: {registration.GetType().Name}.")
};
- ///
- /// Non generic method to get the implementation type for the given
- ///
- /// The given of the interface
- /// The given
- /// The implementation for the given
- /// Unknown passed
- private Type GetTypeNonGeneric(Type type, IRegistration registration) => (Type) GenericMethodCaller.CallPrivate(this, nameof(GetType), type, registration);
-
///
/// Check the given resolve stack for circular dependencies
///
@@ -725,23 +741,14 @@ namespace LightweightIocContainer
/// The given
/// The new resolve stack
/// A circular dependency was detected
- private List CheckForCircularDependencies(List? resolveStack) => CheckForCircularDependencies(typeof(T), resolveStack);
-
- ///
- /// Check the given resolve stack for circular dependencies
- ///
- /// The given
- /// The given resolve stack
- /// The new resolve stack
- /// A circular dependency was detected
- private List CheckForCircularDependencies(Type type, List? resolveStack)
+ private List CheckForCircularDependencies(List? resolveStack)
{
if (resolveStack == null) //first resolve call
- resolveStack = new List {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
+ resolveStack = new List {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(type); //add currently resolving type to the stack
+ resolveStack.Add(typeof(T)); //add currently resolving type to the stack
return resolveStack;
}
diff --git a/LightweightIocContainer/LightweightIocContainer.xml b/LightweightIocContainer/LightweightIocContainer.xml
index 67a2774..f61473c 100644
--- a/LightweightIocContainer/LightweightIocContainer.xml
+++ b/LightweightIocContainer/LightweightIocContainer.xml
@@ -744,6 +744,11 @@
The that is used to register an Interface and extends the with fluent options
+
+
+ A base without generic interface
+
+
The to register either only an interface or only a
@@ -1535,6 +1540,11 @@
that is invoked instead of creating an instance of this the default way
+
+
+ True if is set, false if not
+
+
Pass a that will be invoked instead of creating an instance of this the default way
@@ -1612,14 +1622,14 @@
An internal placeholder that is used to hold types that need to be resolved during the resolving process
-
+
The to be resolved
- The parameters needed to resolve the
+ The parameters needed to resolve the
diff --git a/LightweightIocContainer/ResolvePlaceholders/IInternalToBeResolvedPlaceholder.cs b/LightweightIocContainer/ResolvePlaceholders/IInternalToBeResolvedPlaceholder.cs
new file mode 100644
index 0000000..1f2646c
--- /dev/null
+++ b/LightweightIocContainer/ResolvePlaceholders/IInternalToBeResolvedPlaceholder.cs
@@ -0,0 +1,18 @@
+// Author: Gockner, Simon
+// Created: 2021-12-14
+// Copyright(c) 2021 SimonG. All Rights Reserved.
+
+using System;
+
+namespace LightweightIocContainer.ResolvePlaceholders;
+
+///
+/// An internal placeholder that is used to hold types that need to be resolved during the resolving process
+///
+internal interface IInternalToBeResolvedPlaceholder
+{
+ ///
+ /// The to be resolved
+ ///
+ Type ResolvedType { get; }
+}
\ No newline at end of file
diff --git a/LightweightIocContainer/ResolvePlaceholders/InternalFactoryMethodPlaceholder.cs b/LightweightIocContainer/ResolvePlaceholders/InternalFactoryMethodPlaceholder.cs
new file mode 100644
index 0000000..51005a7
--- /dev/null
+++ b/LightweightIocContainer/ResolvePlaceholders/InternalFactoryMethodPlaceholder.cs
@@ -0,0 +1,31 @@
+// Author: Gockner, Simon
+// Created: 2021-12-14
+// Copyright(c) 2021 SimonG. All Rights Reserved.
+
+using System;
+using LightweightIocContainer.Interfaces;
+using LightweightIocContainer.Interfaces.Registrations;
+
+namespace LightweightIocContainer.ResolvePlaceholders;
+
+///
+/// An internal placeholder that is used to hold factory methods for types that need to be resolved during the resolve process
+///
+internal class InternalFactoryMethodPlaceholder : IInternalToBeResolvedPlaceholder
+{
+ public InternalFactoryMethodPlaceholder(ISingleTypeRegistration singleTypeRegistration)
+ {
+ ResolvedType = singleTypeRegistration.InterfaceType;
+ FactoryMethod = singleTypeRegistration.FactoryMethod ?? throw new InvalidOperationException("Factory method can't be null.");
+ }
+
+ ///
+ /// The to be resolved
+ ///
+ public Type ResolvedType { get; }
+
+ ///
+ /// The
+ ///
+ public Func FactoryMethod { get; }
+}
\ No newline at end of file
diff --git a/LightweightIocContainer/ResolvePlaceholders/InternalToBeResolvedPlaceholder.cs b/LightweightIocContainer/ResolvePlaceholders/InternalToBeResolvedPlaceholder.cs
index dd7ed6f..09842da 100644
--- a/LightweightIocContainer/ResolvePlaceholders/InternalToBeResolvedPlaceholder.cs
+++ b/LightweightIocContainer/ResolvePlaceholders/InternalToBeResolvedPlaceholder.cs
@@ -4,17 +4,19 @@
using System;
using System.Collections.Generic;
+using LightweightIocContainer.Interfaces.Registrations;
namespace LightweightIocContainer.ResolvePlaceholders
{
///
/// An internal placeholder that is used to hold types that need to be resolved during the resolving process
///
- internal class InternalToBeResolvedPlaceholder
+ internal class InternalToBeResolvedPlaceholder : IInternalToBeResolvedPlaceholder
{
- public InternalToBeResolvedPlaceholder(Type resolvedType, List? parameters)
+ public InternalToBeResolvedPlaceholder(Type resolvedType, IRegistration resolvedRegistration, List? parameters)
{
ResolvedType = resolvedType;
+ ResolvedRegistration = resolvedRegistration;
Parameters = parameters;
}
@@ -24,8 +26,13 @@ namespace LightweightIocContainer.ResolvePlaceholders
public Type ResolvedType { get; }
///
- /// The parameters needed to resolve the
+ /// The to be resolved
///
- public List? Parameters { get; }
+ public IRegistration ResolvedRegistration { get; }
+
+ ///
+ /// The parameters needed to resolve the
+ ///
+ public List? Parameters { get; }
}
}
\ No newline at end of file