diff --git a/LightweightIocContainer.Validation/IocValidator.cs b/LightweightIocContainer.Validation/IocValidator.cs index 9cce812..8e9c5a9 100644 --- a/LightweightIocContainer.Validation/IocValidator.cs +++ b/LightweightIocContainer.Validation/IocValidator.cs @@ -71,14 +71,12 @@ public class IocValidator private void TryResolve(Type type, object?[]? arguments, List validationExceptions, bool isFactoryResolve = false) { - try - { - _iocContainer.TryResolveNonGeneric(type, arguments, null, isFactoryResolve); - } - catch (Exception exception) - { + (bool success, object _, Exception? exception) = _iocContainer.TryResolveNonGeneric(type, arguments, null, isFactoryResolve); + if (success) + return; + + if (exception is not null) validationExceptions.Add(exception); - } } private T GetMock() where T : class => new Mock().Object; diff --git a/LightweightIocContainer/IocContainer.cs b/LightweightIocContainer/IocContainer.cs index 0a82dce..10a7712 100644 --- a/LightweightIocContainer/IocContainer.cs +++ b/LightweightIocContainer/IocContainer.cs @@ -129,7 +129,17 @@ public class IocContainer : IIocContainer, IIocResolver /// The current resolve stack /// True if resolve is called from factory, false (default) if not /// An instance of the given registered - private T ResolveInternal(object?[]? arguments, List? resolveStack = null, bool isFactoryResolve = false) => ResolveInstance(TryResolve(arguments, resolveStack, isFactoryResolve)); + private T ResolveInternal(object?[]? arguments, List? resolveStack = null, bool isFactoryResolve = false) + { + (bool success, object resolvedObject, Exception? exception) = TryResolve(arguments, resolveStack, isFactoryResolve); + if (success) + return ResolveInstance(resolvedObject); + + if (exception is not null) + throw exception; + + throw new Exception("Resolve Error"); + } /// /// Tries to resolve the given with the given arguments @@ -145,28 +155,36 @@ public class IocContainer : IIocContainer, IIocResolver /// 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, bool isFactoryResolve = false) + private (bool success, object resolvedObject, Exception? exception) TryResolve(object?[]? arguments, List? resolveStack, bool isFactoryResolve = false) { - IRegistration registration = FindRegistration() ?? throw new TypeNotRegisteredException(typeof(T)); + IRegistration? registration = FindRegistration(); + if (registration == null) + return (false, new object(), new TypeNotRegisteredException(typeof(T))); List internalResolveStack = resolveStack == null ? new List() : new List(resolveStack); - internalResolveStack = CheckForCircularDependencies(internalResolveStack); + (bool success, internalResolveStack, CircularDependencyException? circularDependencyException) = CheckForCircularDependencies(internalResolveStack); + + if (!success && circularDependencyException is not null) + return (false, new object(), circularDependencyException); + + if (!success) + throw new Exception("Invalid return type!"); object? existingInstance = TryGetExistingInstance(registration, arguments); if (existingInstance != null) - return existingInstance; + return (true, existingInstance, null); switch (registration) { - case IWithFactoryInternal { Factory: { } } when !isFactoryResolve: - throw new DirectResolveWithRegisteredFactoryNotAllowed(typeof(T)); - case ISingleTypeRegistration singleTypeRegistration when 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})."); - case ISingleTypeRegistration { FactoryMethod: { } } singleTypeRegistration: - return new InternalFactoryMethodPlaceholder(singleTypeRegistration); + case IWithFactoryInternal { Factory: not null } when !isFactoryResolve: + return (false, new object(), new DirectResolveWithRegisteredFactoryNotAllowed(typeof(T))); + case ISingleTypeRegistration { InterfaceType.IsInterface: true, FactoryMethod: null } singleTypeRegistration: + return (false, new object(), new InvalidRegistrationException($"Can't register an interface without its implementation type or without a factory method (Type: {singleTypeRegistration.InterfaceType}).")); + case ISingleTypeRegistration { FactoryMethod: not null } singleTypeRegistration: + return (true, new InternalFactoryMethodPlaceholder(singleTypeRegistration), null); } - if (registration is IWithParametersInternal { Parameters: { } } registrationWithParameters) + if (registration is IWithParametersInternal { Parameters: not null } registrationWithParameters) arguments = UpdateArgumentsWithRegistrationParameters(registrationWithParameters, arguments); Type registeredType = GetType(registration); @@ -176,7 +194,7 @@ public class IocContainer : IIocContainer, IIocResolver if (registration is IMultitonRegistration multitonRegistration) { if (arguments == null || !arguments.Any()) - throw new MultitonResolveException("Can not resolve multiton without arguments.", registration.InterfaceType); + return (false, new object(), new MultitonResolveException("Can not resolve multiton without arguments.", registration.InterfaceType)); object multitonScopeArgument = TryGetMultitonScopeArgument(multitonRegistration, arguments); @@ -185,12 +203,12 @@ public class IocContainer : IIocContainer, IIocResolver } if (result) - return new InternalToBeResolvedPlaceholder(registeredType, registration, parametersToResolve); + return (true, new InternalToBeResolvedPlaceholder(registeredType, registration, parametersToResolve), null); if (exception != null) - throw exception; + return (false, new object(), exception); - throw new InternalResolveException("Getting resolve stack failed without exception."); + return (false, new object(), new InternalResolveException("Getting resolve stack failed without exception.")); } /// @@ -207,9 +225,15 @@ public class IocContainer : IIocContainer, IIocResolver /// Tried resolving a multiton without scope argument /// No matching constructor for the given found /// Getting resolve stack failed without exception - internal object? TryResolveNonGeneric(Type type, object?[]? arguments, List? resolveStack, bool isFactoryResolve = false) => - GenericMethodCaller.CallPrivate(this, nameof(TryResolve), type, arguments, resolveStack, isFactoryResolve); - + internal (bool success, object resolvedObject, Exception? exception) TryResolveNonGeneric(Type type, object?[]? arguments, List? resolveStack, bool isFactoryResolve = false) + { + object? resolvedValue = GenericMethodCaller.CallPrivate(this, nameof(TryResolve), type, arguments, resolveStack, isFactoryResolve); + if (resolvedValue is not ValueTuple resolvedTuple) + throw new Exception("Invalid return value!"); + + return resolvedTuple; + } + /// /// Recursively resolve a with the given parameters for an /// @@ -513,14 +537,13 @@ public class IocContainer : IIocContainer, IIocResolver if (fittingArgument is InternalResolvePlaceholder) { - try - { - fittingArgument = TryResolveNonGeneric(parameter.ParameterType, null, resolveStack); - } - catch (Exception exception) - { + (bool success, object? resolvedObject, Exception? exception) = TryResolveNonGeneric(parameter.ParameterType, null, resolveStack); + if (success) + fittingArgument = resolvedObject; + else if (!success && exception is not null) exceptions.Add(new ConstructorNotMatchingException(constructor, exception)); - } + else + throw new Exception("Invalid return value!"); if (fittingArgument is InternalResolvePlaceholder && passedArguments != null) { @@ -615,16 +638,16 @@ public class IocContainer : IIocContainer, IIocResolver /// The given /// The new resolve stack /// A circular dependency was detected - private List CheckForCircularDependencies(List? resolveStack) + private (bool success, List resolveStack, CircularDependencyException? exception) CheckForCircularDependencies(List? resolveStack) { if (resolveStack == null) //first resolve call 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 + return (false, new List(), 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 - return resolveStack; + return (true, resolveStack, null); } ///