- use file scoped namespaces

pull/59/head
Simon G 3 years ago
parent e5b984a058
commit 430f58e1c4
  1. 29
      LightweightIocContainer/ActionExtension.cs
  2. 97
      LightweightIocContainer/EnumerableExtension.cs
  3. 71
      LightweightIocContainer/Exceptions/CircularDependencyException.cs
  4. 31
      LightweightIocContainer/Exceptions/ConstructorNotMatchingException.cs
  5. 19
      LightweightIocContainer/Exceptions/GenericMethodNotFoundException.cs
  6. 31
      LightweightIocContainer/Exceptions/IllegalAbstractMethodCreationException.cs
  7. 19
      LightweightIocContainer/Exceptions/InternalResolveException.cs
  8. 19
      LightweightIocContainer/Exceptions/InvalidFactoryRegistrationException.cs
  9. 19
      LightweightIocContainer/Exceptions/InvalidRegistrationException.cs
  10. 53
      LightweightIocContainer/Exceptions/IocContainerException.cs
  11. 29
      LightweightIocContainer/Exceptions/MultipleRegistrationException.cs
  12. 31
      LightweightIocContainer/Exceptions/MultitonResolveException.cs
  13. 43
      LightweightIocContainer/Exceptions/NoMatchingConstructorFoundException.cs
  14. 29
      LightweightIocContainer/Exceptions/NoPublicConstructorFoundException.cs
  15. 29
      LightweightIocContainer/Exceptions/TypeNotRegisteredException.cs
  16. 19
      LightweightIocContainer/Exceptions/UnknownRegistrationException.cs
  17. 13
      LightweightIocContainer/Factories/CustomTypedFactory.cs
  18. 205
      LightweightIocContainer/Factories/TypedFactory.cs
  19. 29
      LightweightIocContainer/Factories/TypedFactoryBase.cs
  20. 81
      LightweightIocContainer/GenericMethodCaller.cs
  21. 57
      LightweightIocContainer/Installers/AssemblyInstaller.cs
  22. 37
      LightweightIocContainer/Installers/FromAssembly.cs
  23. 35
      LightweightIocContainer/Interfaces/Factories/ITypedFactory.cs
  24. 53
      LightweightIocContainer/Interfaces/IIocContainer.cs
  25. 35
      LightweightIocContainer/Interfaces/IIocResolver.cs
  26. 17
      LightweightIocContainer/Interfaces/Installers/IAssemblyInstaller.cs
  27. 19
      LightweightIocContainer/Interfaces/Installers/IIocInstaller.cs
  28. 43
      LightweightIocContainer/Interfaces/Registrations/Fluent/IOnCreate.cs
  29. 49
      LightweightIocContainer/Interfaces/Registrations/Fluent/IWithFactory.cs
  30. 57
      LightweightIocContainer/Interfaces/Registrations/Fluent/IWithParameters.cs
  31. 17
      LightweightIocContainer/Interfaces/Registrations/ILifestyleProvider.cs
  32. 19
      LightweightIocContainer/Interfaces/Registrations/IMultipleMultitonRegistration.cs
  33. 105
      LightweightIocContainer/Interfaces/Registrations/IMultipleRegistration.cs
  34. 33
      LightweightIocContainer/Interfaces/Registrations/IMultitonRegistration.cs
  35. 13
      LightweightIocContainer/Interfaces/Registrations/IOpenGenericRegistration.cs
  36. 17
      LightweightIocContainer/Interfaces/Registrations/IRegistration.cs
  37. 13
      LightweightIocContainer/Interfaces/Registrations/IRegistrationBase.cs
  38. 31
      LightweightIocContainer/Interfaces/Registrations/ISingleTypeRegistration.cs
  39. 19
      LightweightIocContainer/Interfaces/Registrations/ITypedFactoryRegistration.cs
  40. 29
      LightweightIocContainer/Interfaces/Registrations/ITypedRegistration.cs
  41. 1091
      LightweightIocContainer/IocContainer.cs
  42. 33
      LightweightIocContainer/Lifestyle.cs
  43. 79
      LightweightIocContainer/Registrations/MultipleMultitonRegistration.cs
  44. 383
      LightweightIocContainer/Registrations/MultipleRegistration.cs
  45. 73
      LightweightIocContainer/Registrations/MultitonRegistration.cs
  46. 65
      LightweightIocContainer/Registrations/OpenGenericRegistration.cs
  47. 373
      LightweightIocContainer/Registrations/RegistrationBase.cs
  48. 209
      LightweightIocContainer/Registrations/RegistrationFactory.cs
  49. 81
      LightweightIocContainer/Registrations/SingleTypeRegistration.cs
  50. 43
      LightweightIocContainer/Registrations/TypedFactoryRegistration.cs
  51. 109
      LightweightIocContainer/Registrations/TypedRegistration.cs
  52. 13
      LightweightIocContainer/ResolvePlaceholders/InternalResolvePlaceholder.cs
  53. 47
      LightweightIocContainer/ResolvePlaceholders/InternalToBeResolvedPlaceholder.cs
  54. 19
      LightweightIocContainer/TypeExtension.cs
  55. 137
      LightweightIocContainer/Validation/IocValidator.cs
  56. 57
      Test.LightweightIocContainer/ActionExtensionTest.cs
  57. 87
      Test.LightweightIocContainer/AssemblyInstallerTest.cs
  58. 145
      Test.LightweightIocContainer/EnumerableExtensionTest.cs
  59. 387
      Test.LightweightIocContainer/FluentFactoryRegistrationTest.cs
  60. 271
      Test.LightweightIocContainer/IocContainerInterfaceSegregationTest.cs
  61. 227
      Test.LightweightIocContainer/IocContainerParameterRegistrationTest.cs
  62. 215
      Test.LightweightIocContainer/IocContainerRecursionTest.cs
  63. 503
      Test.LightweightIocContainer/IocContainerTest.cs
  64. 247
      Test.LightweightIocContainer/IocValidatorTest.cs
  65. 131
      Test.LightweightIocContainer/MultipleMultitonRegistrationTest.cs
  66. 37
      Test.LightweightIocContainer/OnCreateTest.cs
  67. 85
      Test.LightweightIocContainer/OpenGenericRegistrationTest.cs
  68. 117
      Test.LightweightIocContainer/RegistrationBaseTest.cs
  69. 83
      Test.LightweightIocContainer/SingleTypeRegistrationTest.cs

@ -4,23 +4,22 @@
using System; using System;
namespace LightweightIocContainer namespace LightweightIocContainer;
internal static class ActionExtension
{ {
internal static class ActionExtension /// <summary>
/// Convert an <see cref="Action{T2}"/> to an <see cref="Action{T1}"/> of an inherited <see cref="Type"/>
/// </summary>
/// <typeparam name="T1">The <see cref="Type"/> of the <see cref="Action{T1}"/> to convert to, has to be implemented by <typeparamref name="T2"/></typeparam>
/// <typeparam name="T2">The <see cref="Type"/> of the given <see cref="Action{T2}"/>, has to implement <typeparamref name="T1"/></typeparam>
/// <param name="action">The given <see cref="Action{T2}"/> to convert</param>
/// <returns>An <see cref="Action{T1}"/> converted from the given <see cref="Action{T2}"/></returns>
public static Action<T1>? Convert<T1, T2>(this Action<T2>? action) where T1 : T2
{ {
/// <summary> if (action == null)
/// Convert an <see cref="Action{T2}"/> to an <see cref="Action{T1}"/> of an inherited <see cref="Type"/> return null;
/// </summary>
/// <typeparam name="T1">The <see cref="Type"/> of the <see cref="Action{T1}"/> to convert to, has to be implemented by <typeparamref name="T2"/></typeparam>
/// <typeparam name="T2">The <see cref="Type"/> of the given <see cref="Action{T2}"/>, has to implement <typeparamref name="T1"/></typeparam>
/// <param name="action">The given <see cref="Action{T2}"/> to convert</param>
/// <returns>An <see cref="Action{T1}"/> converted from the given <see cref="Action{T2}"/></returns>
public static Action<T1>? Convert<T1, T2>(this Action<T2>? action) where T1 : T2
{
if (action == null)
return null;
return t => action(t); return t => action(t);
}
} }
} }

@ -6,61 +6,60 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
namespace LightweightIocContainer namespace LightweightIocContainer;
internal static class EnumerableExtension
{ {
internal static class EnumerableExtension /// <summary>
{ /// Returns the first element of a <see cref="IEnumerable{T}"/>, or a new instance of a given <see cref="Type"/> if the <see cref="IEnumerable{T}"/> contains no elements
/// <summary> /// </summary>
/// Returns the first element of a <see cref="IEnumerable{T}"/>, or a new instance of a given <see cref="Type"/> if the <see cref="IEnumerable{T}"/> contains no elements /// <typeparam name="TSource">The source <see cref="Type"/> of the <see cref="IEnumerable{T}"/></typeparam>
/// </summary> /// <typeparam name="TGiven">The given <see cref="Type"/> to return if the <see cref="IEnumerable{T}"/> contains no elements</typeparam>
/// <typeparam name="TSource">The source <see cref="Type"/> of the <see cref="IEnumerable{T}"/></typeparam> /// <param name="source">The given <see cref="IEnumerable{T}"/></param>
/// <typeparam name="TGiven">The given <see cref="Type"/> to return if the <see cref="IEnumerable{T}"/> contains no elements</typeparam> /// <returns>The first element of the <see cref="IEnumerable{T}"/>, or a new instance of a given <see cref="Type"/> if the <see cref="IEnumerable{T}"/> contains no elements</returns>
/// <param name="source">The given <see cref="IEnumerable{T}"/></param> public static TSource FirstOrGiven<TSource, TGiven>(this IEnumerable<TSource> source) where TGiven : TSource, new() =>
/// <returns>The first element of the <see cref="IEnumerable{T}"/>, or a new instance of a given <see cref="Type"/> if the <see cref="IEnumerable{T}"/> contains no elements</returns> source.TryGetFirst<TSource, TGiven>(null);
public static TSource FirstOrGiven<TSource, TGiven>(this IEnumerable<TSource> source) where TGiven : TSource, new() =>
source.TryGetFirst<TSource, TGiven>(null);
/// <summary> /// <summary>
/// Returns the first element of a <see cref="IEnumerable{T}"/> that satisfies a condition, or a new instance of a given <see cref="Type"/> if no such element is found /// Returns the first element of a <see cref="IEnumerable{T}"/> that satisfies a condition, or a new instance of a given <see cref="Type"/> if no such element is found
/// </summary> /// </summary>
/// <typeparam name="TSource">The source <see cref="Type"/> of the <see cref="IEnumerable{T}"/></typeparam> /// <typeparam name="TSource">The source <see cref="Type"/> of the <see cref="IEnumerable{T}"/></typeparam>
/// <typeparam name="TGiven">The given <see cref="Type"/> to return if the <see cref="IEnumerable{T}"/> contains no element that satisfies the given condition</typeparam> /// <typeparam name="TGiven">The given <see cref="Type"/> to return if the <see cref="IEnumerable{T}"/> contains no element that satisfies the given condition</typeparam>
/// <param name="source">The given <see cref="IEnumerable{T}"/></param> /// <param name="source">The given <see cref="IEnumerable{T}"/></param>
/// <param name="predicate">A function to test each element for a condition</param> /// <param name="predicate">A function to test each element for a condition</param>
/// <returns>The first element of the <see cref="IEnumerable{T}"/> that satisfies a condition, or a new instance of the given <see cref="Type"/> if no such element is found</returns> /// <returns>The first element of the <see cref="IEnumerable{T}"/> that satisfies a condition, or a new instance of the given <see cref="Type"/> if no such element is found</returns>
public static TSource FirstOrGiven<TSource, TGiven>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) where TGiven : TSource, new() => public static TSource FirstOrGiven<TSource, TGiven>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) where TGiven : TSource, new() =>
source.TryGetFirst<TSource, TGiven>(predicate); source.TryGetFirst<TSource, TGiven>(predicate);
/// <summary> /// <summary>
/// Tries to get the first element of the given <see cref="IEnumerable{T}"/> or creates a new element of a given <see cref="Type"/> when no element is found /// Tries to get the first element of the given <see cref="IEnumerable{T}"/> or creates a new element of a given <see cref="Type"/> when no element is found
/// </summary> /// </summary>
/// <typeparam name="TSource">The source <see cref="Type"/> of the <see cref="IEnumerable{T}"/></typeparam> /// <typeparam name="TSource">The source <see cref="Type"/> of the <see cref="IEnumerable{T}"/></typeparam>
/// <typeparam name="TGiven">The given <see cref="Type"/> to create a new element when no fitting element is found</typeparam> /// <typeparam name="TGiven">The given <see cref="Type"/> to create a new element when no fitting element is found</typeparam>
/// <param name="source">The given <see cref="IEnumerable{T}"/></param> /// <param name="source">The given <see cref="IEnumerable{T}"/></param>
/// <param name="predicate">A function to test each element for a condition</param> /// <param name="predicate">A function to test each element for a condition</param>
/// <returns>The first element of the <see cref="IEnumerable{T}"/> or a new instance of the given <see cref="Type"/> when no element is found</returns> /// <returns>The first element of the <see cref="IEnumerable{T}"/> or a new instance of the given <see cref="Type"/> when no element is found</returns>
private static TSource TryGetFirst<TSource, TGiven>(this IEnumerable<TSource> source, Func<TSource, bool>? predicate) where TGiven : TSource, new() private static TSource TryGetFirst<TSource, TGiven>(this IEnumerable<TSource> source, Func<TSource, bool>? predicate) where TGiven : TSource, new()
{
try
{ {
try return predicate == null ? source.First() : source.First(predicate);
{
return predicate == null ? source.First() : source.First(predicate);
}
catch (Exception)
{
return new TGiven();
}
} }
catch (Exception)
/// <summary>
/// Executes an <see cref="Action{T}"/> for each item in an <see cref="IEnumerable{T}"/>
/// </summary>
/// <param name="enumerable">The <see cref="IEnumerable{T}"/></param>
/// <param name="action">The <see cref="Action{T}"/></param>
/// <typeparam name="T">The <see cref="Type"/> of the items in the <see cref="IEnumerable{T}"/></typeparam>
public static void ForEach<T>(this IEnumerable<T> enumerable, Action<T> action)
{ {
foreach (T item in enumerable) return new TGiven();
action(item);
} }
} }
/// <summary>
/// Executes an <see cref="Action{T}"/> for each item in an <see cref="IEnumerable{T}"/>
/// </summary>
/// <param name="enumerable">The <see cref="IEnumerable{T}"/></param>
/// <param name="action">The <see cref="Action{T}"/></param>
/// <typeparam name="T">The <see cref="Type"/> of the items in the <see cref="IEnumerable{T}"/></typeparam>
public static void ForEach<T>(this IEnumerable<T> enumerable, Action<T> action)
{
foreach (T item in enumerable)
action(item);
}
} }

@ -7,55 +7,54 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
namespace LightweightIocContainer.Exceptions namespace LightweightIocContainer.Exceptions;
/// <summary>
/// A circular dependency was detected during <see cref="IocContainer.Resolve{T}()"/>
/// </summary>
internal class CircularDependencyException : IocContainerException
{ {
/// <summary> /// <summary>
/// A circular dependency was detected during <see cref="IocContainer.Resolve{T}()"/> /// A circular dependency was detected during <see cref="IocContainer.Resolve{T}()"/>
/// </summary> /// </summary>
internal class CircularDependencyException : IocContainerException /// <param name="resolvingType">The currently resolving <see cref="Type"/></param>
/// <param name="resolveStack">The resolve stack at the time the <see cref="CircularDependencyException"/> was thrown</param>
public CircularDependencyException(Type resolvingType, List<Type> resolveStack)
{ {
/// <summary> ResolvingType = resolvingType;
/// A circular dependency was detected during <see cref="IocContainer.Resolve{T}()"/> ResolveStack = resolveStack;
/// </summary> }
/// <param name="resolvingType">The currently resolving <see cref="Type"/></param>
/// <param name="resolveStack">The resolve stack at the time the <see cref="CircularDependencyException"/> was thrown</param>
public CircularDependencyException(Type resolvingType, List<Type> resolveStack)
{
ResolvingType = resolvingType;
ResolveStack = resolveStack;
}
/// <summary> /// <summary>
/// The currently resolving <see cref="Type"/> /// The currently resolving <see cref="Type"/>
/// </summary> /// </summary>
public Type ResolvingType { get; } public Type ResolvingType { get; }
/// <summary> /// <summary>
/// The resolve stack at the time the <see cref="CircularDependencyException"/> was thrown /// The resolve stack at the time the <see cref="CircularDependencyException"/> was thrown
/// </summary> /// </summary>
public List<Type> ResolveStack { get; } public List<Type> ResolveStack { get; }
/// <summary> /// <summary>
/// The exception message /// The exception message
/// </summary> /// </summary>
public override string Message public override string Message
{
get
{ {
get StringBuilder message = new($"Circular dependency has been detected when trying to resolve `{ResolvingType}`.\n");
{ if (!ResolveStack.Any())
StringBuilder message = new($"Circular dependency has been detected when trying to resolve `{ResolvingType}`.\n"); return message.ToString();
if (!ResolveStack.Any())
return message.ToString();
message.Append("Resolve stack that resulted in the circular dependency:\n"); message.Append("Resolve stack that resulted in the circular dependency:\n");
message.Append($"\t`{ResolvingType}` resolved as dependency of\n"); message.Append($"\t`{ResolvingType}` resolved as dependency of\n");
for (int i = ResolveStack.Count - 1; i >= 1 ; i--) for (int i = ResolveStack.Count - 1; i >= 1 ; i--)
message.Append($"\t`{ResolveStack[i]}` resolved as dependency of\n"); message.Append($"\t`{ResolveStack[i]}` resolved as dependency of\n");
message.Append($"\t`{ResolveStack[0]}` which is the root type being resolved."); message.Append($"\t`{ResolveStack[0]}` which is the root type being resolved.");
return message.ToString(); return message.ToString();
}
} }
} }
} }

@ -5,25 +5,24 @@
using System; using System;
using System.Reflection; using System.Reflection;
namespace LightweightIocContainer.Exceptions namespace LightweightIocContainer.Exceptions;
/// <summary>
/// The constructor does not match the given or resolvable arguments
/// </summary>
internal class ConstructorNotMatchingException : IocContainerException
{ {
/// <summary> /// <summary>
/// The constructor does not match the given or resolvable arguments /// The constructor does not match the given or resolvable arguments
/// </summary> /// </summary>
internal class ConstructorNotMatchingException : IocContainerException /// <param name="constructor">The constructor that does not match</param>
{ /// <param name="exception">The inner exception</param>
/// <summary> public ConstructorNotMatchingException(ConstructorInfo constructor, Exception exception)
/// The constructor does not match the given or resolvable arguments : base($"Constructor {constructor} does not match the given or resolvable arguments.", exception) =>
/// </summary> Constructor = constructor;
/// <param name="constructor">The constructor that does not match</param>
/// <param name="exception">The inner exception</param>
public ConstructorNotMatchingException(ConstructorInfo constructor, Exception exception)
: base($"Constructor {constructor} does not match the given or resolvable arguments.", exception) =>
Constructor = constructor;
/// <summary> /// <summary>
/// The constructor that does not match /// The constructor that does not match
/// </summary> /// </summary>
public ConstructorInfo Constructor { get; } public ConstructorInfo Constructor { get; }
}
} }

@ -4,21 +4,20 @@
using System; using System;
namespace LightweightIocContainer.Exceptions namespace LightweightIocContainer.Exceptions;
/// <summary>
/// Could not find generic method
/// </summary>
internal class GenericMethodNotFoundException : Exception
{ {
/// <summary> /// <summary>
/// Could not find generic method /// Could not find generic method
/// </summary> /// </summary>
internal class GenericMethodNotFoundException : Exception /// <param name="functionName">The name of the generic method</param>
public GenericMethodNotFoundException(string functionName)
: base($"Could not find function {functionName}")
{ {
/// <summary>
/// Could not find generic method
/// </summary>
/// <param name="functionName">The name of the generic method</param>
public GenericMethodNotFoundException(string functionName)
: base($"Could not find function {functionName}")
{
}
} }
} }

@ -4,25 +4,24 @@
using System.Reflection; using System.Reflection;
namespace LightweightIocContainer.Exceptions namespace LightweightIocContainer.Exceptions;
/// <summary>
/// The creation of the abstract method is illegal in its current state
/// </summary>
internal class IllegalAbstractMethodCreationException : IocContainerException
{ {
/// <summary> /// <summary>
/// The creation of the abstract method is illegal in its current state /// The creation of the abstract method is illegal in its current state
/// </summary> /// </summary>
internal class IllegalAbstractMethodCreationException : IocContainerException /// <param name="message">The exception message</param>
{ /// <param name="method">The method that is illegal to create</param>
/// <summary> public IllegalAbstractMethodCreationException(string message, MethodInfo method)
/// The creation of the abstract method is illegal in its current state : base(message) =>
/// </summary> Method = method;
/// <param name="message">The exception message</param>
/// <param name="method">The method that is illegal to create</param>
public IllegalAbstractMethodCreationException(string message, MethodInfo method)
: base(message) =>
Method = method;
/// <summary> /// <summary>
/// The Method whose creation is illegal /// The Method whose creation is illegal
/// </summary> /// </summary>
public MethodInfo Method { get; } public MethodInfo Method { get; }
}
} }

@ -4,21 +4,20 @@
using LightweightIocContainer.Interfaces; using LightweightIocContainer.Interfaces;
namespace LightweightIocContainer.Exceptions namespace LightweightIocContainer.Exceptions;
/// <summary>
/// An internal Error happened while the <see cref="IIocContainer"/> tried to resolve an instance
/// </summary>
internal class InternalResolveException : IocContainerException
{ {
/// <summary> /// <summary>
/// An internal Error happened while the <see cref="IIocContainer"/> tried to resolve an instance /// An internal Error happened while the <see cref="IIocContainer"/> tried to resolve an instance
/// </summary> /// </summary>
internal class InternalResolveException : IocContainerException /// <param name="message">The exception message</param>
public InternalResolveException(string message)
: base(message)
{ {
/// <summary>
/// An internal Error happened while the <see cref="IIocContainer"/> tried to resolve an instance
/// </summary>
/// <param name="message">The exception message</param>
public InternalResolveException(string message)
: base(message)
{
}
} }
} }

@ -2,21 +2,20 @@
// Created: 2019-05-20 // Created: 2019-05-20
// Copyright(c) 2019 SimonG. All Rights Reserved. // Copyright(c) 2019 SimonG. All Rights Reserved.
namespace LightweightIocContainer.Exceptions namespace LightweightIocContainer.Exceptions;
/// <summary>
/// The registration of a Factory is not valid
/// </summary>
internal class InvalidFactoryRegistrationException : InvalidRegistrationException
{ {
/// <summary> /// <summary>
/// The registration of a Factory is not valid /// The registration of a Factory is not valid
/// </summary> /// </summary>
internal class InvalidFactoryRegistrationException : InvalidRegistrationException /// <param name="message">The exception message</param>
public InvalidFactoryRegistrationException(string message)
: base(message)
{ {
/// <summary>
/// The registration of a Factory is not valid
/// </summary>
/// <param name="message">The exception message</param>
public InvalidFactoryRegistrationException(string message)
: base(message)
{
}
} }
} }

@ -2,21 +2,20 @@
// Created: 2019-05-20 // Created: 2019-05-20
// Copyright(c) 2019 SimonG. All Rights Reserved. // Copyright(c) 2019 SimonG. All Rights Reserved.
namespace LightweightIocContainer.Exceptions namespace LightweightIocContainer.Exceptions;
/// <summary>
/// The registration is not valid
/// </summary>
internal class InvalidRegistrationException : IocContainerException
{ {
/// <summary> /// <summary>
/// The registration is not valid /// The registration is not valid
/// </summary> /// </summary>
internal class InvalidRegistrationException : IocContainerException /// <param name="message">The exception message</param>
public InvalidRegistrationException(string message)
: base(message)
{ {
/// <summary>
/// The registration is not valid
/// </summary>
/// <param name="message">The exception message</param>
public InvalidRegistrationException(string message)
: base(message)
{
}
} }
} }

@ -5,38 +5,37 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
namespace LightweightIocContainer.Exceptions namespace LightweightIocContainer.Exceptions;
/// <summary>
/// A base <see cref="Exception"/> for the <see cref="LightweightIocContainer"/>
/// </summary>
public abstract class IocContainerException : Exception
{ {
/// <summary> /// <summary>
/// A base <see cref="Exception"/> for the <see cref="LightweightIocContainer"/> /// A base <see cref="Exception"/> for the <see cref="LightweightIocContainer"/>
/// </summary> /// </summary>
public abstract class IocContainerException : Exception protected IocContainerException() => InnerExceptions = new List<Exception>();
{
/// <summary>
/// A base <see cref="Exception"/> for the <see cref="LightweightIocContainer"/>
/// </summary>
protected IocContainerException() => InnerExceptions = new List<Exception>();
/// <summary> /// <summary>
/// A base <see cref="Exception"/> for the <see cref="LightweightIocContainer"/> /// A base <see cref="Exception"/> for the <see cref="LightweightIocContainer"/>
/// </summary> /// </summary>
/// <param name="message">The message of the <see cref="Exception"/></param> /// <param name="message">The message of the <see cref="Exception"/></param>
protected IocContainerException(string message) protected IocContainerException(string message)
: base(message) => : base(message) =>
InnerExceptions = new List<Exception>(); InnerExceptions = new List<Exception>();
/// <summary> /// <summary>
/// A base <see cref="Exception"/> for the <see cref="LightweightIocContainer"/> /// A base <see cref="Exception"/> for the <see cref="LightweightIocContainer"/>
/// </summary> /// </summary>
/// <param name="message">The message of the <see cref="Exception"/></param> /// <param name="message">The message of the <see cref="Exception"/></param>
/// <param name="innerException">The inner <see cref="Exception"/></param> /// <param name="innerException">The inner <see cref="Exception"/></param>
protected IocContainerException(string message, Exception innerException) protected IocContainerException(string message, Exception innerException)
: base(message, innerException) => : base(message, innerException) =>
InnerExceptions = new List<Exception> {innerException}; InnerExceptions = new List<Exception> {innerException};
/// <summary> /// <summary>
/// The inner exceptions of the <see cref="IocContainerException"/> /// The inner exceptions of the <see cref="IocContainerException"/>
/// </summary> /// </summary>
public List<Exception> InnerExceptions { get; protected init; } public List<Exception> InnerExceptions { get; protected init; }
}
} }

@ -5,24 +5,23 @@
using System; using System;
using LightweightIocContainer.Interfaces; using LightweightIocContainer.Interfaces;
namespace LightweightIocContainer.Exceptions namespace LightweightIocContainer.Exceptions;
/// <summary>
/// The <see cref="System.Type"/> is already registered differently in this <see cref="IIocContainer"/>
/// </summary>
internal class MultipleRegistrationException : IocContainerException
{ {
/// <summary> /// <summary>
/// The <see cref="System.Type"/> is already registered differently in this <see cref="IIocContainer"/> /// The <see cref="System.Type"/> is already registered differently in this <see cref="IIocContainer"/>
/// </summary> /// </summary>
internal class MultipleRegistrationException : IocContainerException /// <param name="type">The <see cref="System.Type"/> that is already registered in this <see cref="IIocContainer"/></param>
{ public MultipleRegistrationException(Type type)
/// <summary> : base($"Type {type.Name} is already registered differently in this IocContainer.") =>
/// The <see cref="System.Type"/> is already registered differently in this <see cref="IIocContainer"/> Type = type;
/// </summary>
/// <param name="type">The <see cref="System.Type"/> that is already registered in this <see cref="IIocContainer"/></param>
public MultipleRegistrationException(Type type)
: base($"Type {type.Name} is already registered differently in this IocContainer.") =>
Type = type;
/// <summary> /// <summary>
/// The registered <see cref="System.Type"/> /// The registered <see cref="System.Type"/>
/// </summary> /// </summary>
public Type Type { get; } public Type Type { get; }
}
} }

@ -4,25 +4,24 @@
using System; using System;
namespace LightweightIocContainer.Exceptions namespace LightweightIocContainer.Exceptions;
/// <summary>
/// An error happened while trying to resolve a multiton
/// </summary>
internal class MultitonResolveException : InternalResolveException
{ {
/// <summary> /// <summary>
/// An error happened while trying to resolve a multiton /// An error happened while trying to resolve a multiton
/// </summary> /// </summary>
internal class MultitonResolveException : InternalResolveException /// <param name="message">The exception message</param>
{ /// <param name="type">The <see cref="System.Type"/> of the multiton that's responsible for the exception</param>
/// <summary> public MultitonResolveException(string message, Type type)
/// An error happened while trying to resolve a multiton : base(message) =>
/// </summary> Type = type;
/// <param name="message">The exception message</param>
/// <param name="type">The <see cref="System.Type"/> of the multiton that's responsible for the exception</param>
public MultitonResolveException(string message, Type type)
: base(message) =>
Type = type;
/// <summary> /// <summary>
/// The <see cref="System.Type"/> of the multiton that's responsible for the exception /// The <see cref="System.Type"/> of the multiton that's responsible for the exception
/// </summary> /// </summary>
public Type Type { get; } public Type Type { get; }
}
} }

@ -5,34 +5,33 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
namespace LightweightIocContainer.Exceptions namespace LightweightIocContainer.Exceptions;
/// <summary>
/// No matching constructor was found for the given or resolvable arguments
/// </summary>
internal class NoMatchingConstructorFoundException : IocContainerException
{ {
/// <summary> /// <summary>
/// No matching constructor was found for the given or resolvable arguments /// No matching constructor was found for the given or resolvable arguments
/// </summary> /// </summary>
internal class NoMatchingConstructorFoundException : IocContainerException /// <param name="type">The <see cref="Type"/> with no matching constructor</param>
public NoMatchingConstructorFoundException(Type type)
: base($"No matching constructor for {type} found.")
{ {
/// <summary> Type = type;
/// No matching constructor was found for the given or resolvable arguments InnerExceptions = new List<Exception>();
/// </summary> }
/// <param name="type">The <see cref="Type"/> with no matching constructor</param>
public NoMatchingConstructorFoundException(Type type)
: base($"No matching constructor for {type} found.")
{
Type = type;
InnerExceptions = new List<Exception>();
}
/// <summary> /// <summary>
/// The <see cref="Type"/> with no matching constructor /// The <see cref="Type"/> with no matching constructor
/// </summary> /// </summary>
public Type Type { get; } public Type Type { get; }
/// <summary> /// <summary>
/// Add an inner exception to the <see cref="IocContainerException.InnerExceptions"/> /// Add an inner exception to the <see cref="IocContainerException.InnerExceptions"/>
/// </summary> /// </summary>
/// <param name="exception">The <see cref="ConstructorNotMatchingException"/></param> /// <param name="exception">The <see cref="ConstructorNotMatchingException"/></param>
public void AddInnerException(ConstructorNotMatchingException exception) => InnerExceptions.Add(exception); public void AddInnerException(ConstructorNotMatchingException exception) => InnerExceptions.Add(exception);
}
} }

@ -4,24 +4,23 @@
using System; using System;
namespace LightweightIocContainer.Exceptions namespace LightweightIocContainer.Exceptions;
/// <summary>
/// No public constructor can be found for a <see cref="Type"/>
/// </summary>
internal class NoPublicConstructorFoundException : IocContainerException
{ {
/// <summary> /// <summary>
/// No public constructor can be found for a <see cref="Type"/> /// No public constructor can be found for a <see cref="Type"/>
/// </summary> /// </summary>
internal class NoPublicConstructorFoundException : IocContainerException /// <param name="type">The <see cref="Type"/> with no public constructor</param>
{ public NoPublicConstructorFoundException(Type type)
/// <summary> : base($"No public constructor for {type} found.") =>
/// No public constructor can be found for a <see cref="Type"/> Type = type;
/// </summary>
/// <param name="type">The <see cref="Type"/> with no public constructor</param>
public NoPublicConstructorFoundException(Type type)
: base($"No public constructor for {type} found.") =>
Type = type;
/// <summary> /// <summary>
/// The <see cref="Type"/> with no public constructor /// The <see cref="Type"/> with no public constructor
/// </summary> /// </summary>
public Type Type { get; } public Type Type { get; }
}
} }

@ -5,24 +5,23 @@
using System; using System;
using LightweightIocContainer.Interfaces; using LightweightIocContainer.Interfaces;
namespace LightweightIocContainer.Exceptions namespace LightweightIocContainer.Exceptions;
/// <summary>
/// The <see cref="System.Type"/> is not registered in this <see cref="IIocContainer"/>
/// </summary>
internal class TypeNotRegisteredException : IocContainerException
{ {
/// <summary> /// <summary>
/// The <see cref="System.Type"/> is not registered in this <see cref="IIocContainer"/> /// The <see cref="System.Type"/> is not registered in this <see cref="IIocContainer"/>
/// </summary> /// </summary>
internal class TypeNotRegisteredException : IocContainerException /// <param name="type">The unregistered <see cref="System.Type"/></param>
{ public TypeNotRegisteredException(Type type)
/// <summary> : base($"Type {type.Name} is not registered in this IocContainer.") =>
/// The <see cref="System.Type"/> is not registered in this <see cref="IIocContainer"/> Type = type;
/// </summary>
/// <param name="type">The unregistered <see cref="System.Type"/></param>
public TypeNotRegisteredException(Type type)
: base($"Type {type.Name} is not registered in this IocContainer.") =>
Type = type;
/// <summary> /// <summary>
/// The unregistered <see cref="System.Type"/> /// The unregistered <see cref="System.Type"/>
/// </summary> /// </summary>
public Type Type { get; } public Type Type { get; }
}
} }

@ -4,21 +4,20 @@
using LightweightIocContainer.Interfaces.Registrations; using LightweightIocContainer.Interfaces.Registrations;
namespace LightweightIocContainer.Exceptions namespace LightweightIocContainer.Exceptions;
/// <summary>
/// An unknown <see cref="IRegistration"/> was used
/// </summary>
internal class UnknownRegistrationException : IocContainerException
{ {
/// <summary> /// <summary>
/// An unknown <see cref="IRegistration"/> was used /// An unknown <see cref="IRegistration"/> was used
/// </summary> /// </summary>
internal class UnknownRegistrationException : IocContainerException /// <param name="message">The exception message</param>
public UnknownRegistrationException(string message)
: base(message)
{ {
/// <summary>
/// An unknown <see cref="IRegistration"/> was used
/// </summary>
/// <param name="message">The exception message</param>
public UnknownRegistrationException(string message)
: base(message)
{
}
} }
} }

@ -4,13 +4,12 @@
using LightweightIocContainer.Interfaces.Factories; using LightweightIocContainer.Interfaces.Factories;
namespace LightweightIocContainer.Factories namespace LightweightIocContainer.Factories;
/// <summary>
/// <see cref="ITypedFactory"/> implementation for custom implemented factories
/// </summary>
public class CustomTypedFactory<TFactory> : TypedFactoryBase<TFactory>
{ {
/// <summary>
/// <see cref="ITypedFactory"/> implementation for custom implemented factories
/// </summary>
public class CustomTypedFactory<TFactory> : TypedFactoryBase<TFactory>
{
}
} }

@ -10,133 +10,132 @@ using LightweightIocContainer.Exceptions;
using LightweightIocContainer.Interfaces; using LightweightIocContainer.Interfaces;
using LightweightIocContainer.Interfaces.Factories; using LightweightIocContainer.Interfaces.Factories;
namespace LightweightIocContainer.Factories namespace LightweightIocContainer.Factories;
/// <summary>
/// Class to help implement an abstract typed factory
/// </summary>
/// <typeparam name="TFactory">The type of the abstract factory</typeparam>
public class TypedFactory<TFactory> : TypedFactoryBase<TFactory>, ITypedFactory<TFactory>
{ {
private const string CLEAR_MULTITON_INSTANCE_METHOD_NAME = "ClearMultitonInstance";
/// <summary> /// <summary>
/// Class to help implement an abstract typed factory /// The
/// </summary> /// </summary>
/// <typeparam name="TFactory">The type of the abstract factory</typeparam> /// <param name="container">The current instance of the <see cref="IIocContainer"/></param>
public class TypedFactory<TFactory> : TypedFactoryBase<TFactory>, ITypedFactory<TFactory> public TypedFactory(IocContainer container) => Factory = CreateFactory(container);
{
private const string CLEAR_MULTITON_INSTANCE_METHOD_NAME = "ClearMultitonInstance"; /// <summary>
/// The implemented abstract typed factory/>
/// <summary> /// </summary>
/// The public TFactory Factory { get; set; }
/// </summary>
/// <param name="container">The current instance of the <see cref="IIocContainer"/></param>
public TypedFactory(IocContainer container) => Factory = CreateFactory(container);
/// <summary>
/// The implemented abstract typed factory/>
/// </summary>
public TFactory Factory { get; set; }
/// <summary> /// <summary>
/// Creates the factory from the given abstract factory type /// Creates the factory from the given abstract factory type
/// </summary> /// </summary>
/// <exception cref="InvalidFactoryRegistrationException">Factory registration is invalid</exception> /// <exception cref="InvalidFactoryRegistrationException">Factory registration is invalid</exception>
/// <exception cref="IllegalAbstractMethodCreationException">Creation of abstract methods are illegal in their current state</exception> /// <exception cref="IllegalAbstractMethodCreationException">Creation of abstract methods are illegal in their current state</exception>
private TFactory CreateFactory(IocContainer container) private TFactory CreateFactory(IocContainer container)
{ {
Type factoryType = typeof(TFactory); Type factoryType = typeof(TFactory);
AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("Factory"), AssemblyBuilderAccess.Run); AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("Factory"), AssemblyBuilderAccess.Run);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("Factory"); ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("Factory");
TypeBuilder typeBuilder = moduleBuilder.DefineType($"TypedFactory.{factoryType.Name}"); TypeBuilder typeBuilder = moduleBuilder.DefineType($"TypedFactory.{factoryType.Name}");
typeBuilder.AddInterfaceImplementation(factoryType); typeBuilder.AddInterfaceImplementation(factoryType);
//add `private readonly IIocContainer _container` field //add `private readonly IIocContainer _container` field
FieldBuilder containerFieldBuilder = typeBuilder.DefineField("_container", typeof(IocContainer), FieldAttributes.Private | FieldAttributes.InitOnly); FieldBuilder containerFieldBuilder = typeBuilder.DefineField("_container", typeof(IocContainer), FieldAttributes.Private | FieldAttributes.InitOnly);
//add ctor //add ctor
ConstructorBuilder constructorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, new[] {typeof(IocContainer)}); ConstructorBuilder constructorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, new[] {typeof(IocContainer)});
ILGenerator constructorGenerator = constructorBuilder.GetILGenerator(); ILGenerator constructorGenerator = constructorBuilder.GetILGenerator();
constructorGenerator.Emit(OpCodes.Ldarg_0); constructorGenerator.Emit(OpCodes.Ldarg_0);
constructorGenerator.Emit(OpCodes.Ldarg_1); constructorGenerator.Emit(OpCodes.Ldarg_1);
constructorGenerator.Emit(OpCodes.Stfld, containerFieldBuilder); //set `_container` field constructorGenerator.Emit(OpCodes.Stfld, containerFieldBuilder); //set `_container` field
constructorGenerator.Emit(OpCodes.Ret); constructorGenerator.Emit(OpCodes.Ret);
foreach (MethodInfo createMethod in CreateMethods) foreach (MethodInfo createMethod in CreateMethods)
{ {
//create a method that looks like this //create a method that looks like this
//public `createMethod.ReturnType` Create(`createMethod.GetParameters()`) //public `createMethod.ReturnType` Create(`createMethod.GetParameters()`)
//{ //{
// return IIocContainer.Resolve(`createMethod.ReturnType`, params); // return IIocContainer.Resolve(`createMethod.ReturnType`, params);
//} //}
ParameterInfo[] args = createMethod.GetParameters(); ParameterInfo[] args = createMethod.GetParameters();
MethodBuilder methodBuilder = typeBuilder.DefineMethod(createMethod.Name, MethodAttributes.Public | MethodAttributes.Virtual, MethodBuilder methodBuilder = typeBuilder.DefineMethod(createMethod.Name, MethodAttributes.Public | MethodAttributes.Virtual,
createMethod.ReturnType, (from arg in args select arg.ParameterType).ToArray()); createMethod.ReturnType, (from arg in args select arg.ParameterType).ToArray());
typeBuilder.DefineMethodOverride(methodBuilder, createMethod); typeBuilder.DefineMethodOverride(methodBuilder, createMethod);
ILGenerator generator = methodBuilder.GetILGenerator(); ILGenerator generator = methodBuilder.GetILGenerator();
generator.Emit(OpCodes.Ldarg_0); generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldfld, containerFieldBuilder); generator.Emit(OpCodes.Ldfld, containerFieldBuilder);
if (args.Any()) if (args.Any())
{ {
generator.Emit(OpCodes.Ldc_I4_S, args.Length); generator.Emit(OpCodes.Ldc_I4_S, args.Length);
generator.Emit(OpCodes.Newarr, typeof(object)); generator.Emit(OpCodes.Newarr, typeof(object));
for (int i = 0; i < args.Length; i++) for (int i = 0; i < args.Length; i++)
{
generator.Emit(OpCodes.Dup);
generator.Emit(OpCodes.Ldc_I4_S, i);
generator.Emit(OpCodes.Ldarg_S, i + 1);
generator.Emit(OpCodes.Box, args[i].ParameterType); //Boxing is only needed for simple datatypes, but for now it is not a problem to box everything
generator.Emit(OpCodes.Stelem_Ref);
}
}
else
{ {
MethodInfo emptyArray = typeof(Array).GetMethod(nameof(Array.Empty))!.MakeGenericMethod(typeof(object)); generator.Emit(OpCodes.Dup);
generator.EmitCall(OpCodes.Call, emptyArray, null); generator.Emit(OpCodes.Ldc_I4_S, i);
generator.Emit(OpCodes.Ldarg_S, i + 1);
generator.Emit(OpCodes.Box, args[i].ParameterType); //Boxing is only needed for simple datatypes, but for now it is not a problem to box everything
generator.Emit(OpCodes.Stelem_Ref);
} }
generator.EmitCall(OpCodes.Call, typeof(IocContainer).GetMethod(nameof(IocContainer.FactoryResolve), new[] { typeof(object[]) })!.MakeGenericMethod(createMethod.ReturnType), null);
generator.Emit(OpCodes.Castclass, createMethod.ReturnType);
generator.Emit(OpCodes.Ret);
} }
else
//if factory contains a method to clear multiton instances
MethodInfo? multitonClearMethod = factoryType.GetMethods().FirstOrDefault(m => m.Name.Equals(CLEAR_MULTITON_INSTANCE_METHOD_NAME));
if (multitonClearMethod != null)
{ {
//create a method that looks like this MethodInfo emptyArray = typeof(Array).GetMethod(nameof(Array.Empty))!.MakeGenericMethod(typeof(object));
//public void ClearMultitonInstance<typeToClear>() generator.EmitCall(OpCodes.Call, emptyArray, null);
//{ }
// IIocContainer.ClearMultitonInstances<typeToClear>();
//}
if (multitonClearMethod.IsGenericMethod) generator.EmitCall(OpCodes.Call, typeof(IocContainer).GetMethod(nameof(IocContainer.FactoryResolve), new[] { typeof(object[]) })!.MakeGenericMethod(createMethod.ReturnType), null);
{ generator.Emit(OpCodes.Castclass, createMethod.ReturnType);
Type? typeToClear = multitonClearMethod.GetGenericArguments().FirstOrDefault(); generator.Emit(OpCodes.Ret);
if (typeToClear == null) }
throw new IllegalAbstractMethodCreationException("No Type to clear specified.", multitonClearMethod);
MethodBuilder multitonClearMethodBuilder = typeBuilder.DefineMethod(multitonClearMethod.Name, MethodAttributes.Public | MethodAttributes.Virtual, //if factory contains a method to clear multiton instances
multitonClearMethod.ReturnType, null); MethodInfo? multitonClearMethod = factoryType.GetMethods().FirstOrDefault(m => m.Name.Equals(CLEAR_MULTITON_INSTANCE_METHOD_NAME));
multitonClearMethodBuilder.DefineGenericParameters(typeToClear.Name); if (multitonClearMethod != null)
{
//create a method that looks like this
//public void ClearMultitonInstance<typeToClear>()
//{
// IIocContainer.ClearMultitonInstances<typeToClear>();
//}
typeBuilder.DefineMethodOverride(multitonClearMethodBuilder, multitonClearMethod); if (multitonClearMethod.IsGenericMethod)
{
Type? typeToClear = multitonClearMethod.GetGenericArguments().FirstOrDefault();
if (typeToClear == null)
throw new IllegalAbstractMethodCreationException("No Type to clear specified.", multitonClearMethod);
ILGenerator multitonClearGenerator = multitonClearMethodBuilder.GetILGenerator(); MethodBuilder multitonClearMethodBuilder = typeBuilder.DefineMethod(multitonClearMethod.Name, MethodAttributes.Public | MethodAttributes.Virtual,
multitonClearGenerator.Emit(OpCodes.Ldarg_0); multitonClearMethod.ReturnType, null);
multitonClearGenerator.Emit(OpCodes.Ldfld, containerFieldBuilder); multitonClearMethodBuilder.DefineGenericParameters(typeToClear.Name);
multitonClearGenerator.EmitCall(OpCodes.Call, typeof(IocContainer).GetMethod(nameof(IocContainer.ClearMultitonInstances))!.MakeGenericMethod(typeToClear), null); typeBuilder.DefineMethodOverride(multitonClearMethodBuilder, multitonClearMethod);
multitonClearGenerator.Emit(OpCodes.Ret);
} ILGenerator multitonClearGenerator = multitonClearMethodBuilder.GetILGenerator();
else multitonClearGenerator.Emit(OpCodes.Ldarg_0);
{ multitonClearGenerator.Emit(OpCodes.Ldfld, containerFieldBuilder);
throw new IllegalAbstractMethodCreationException("No Type to clear specified.", multitonClearMethod);
}
}
return Creator.CreateInstance<TFactory>(typeBuilder.CreateTypeInfo()!.AsType(), container); multitonClearGenerator.EmitCall(OpCodes.Call, typeof(IocContainer).GetMethod(nameof(IocContainer.ClearMultitonInstances))!.MakeGenericMethod(typeToClear), null);
multitonClearGenerator.Emit(OpCodes.Ret);
}
else
{
throw new IllegalAbstractMethodCreationException("No Type to clear specified.", multitonClearMethod);
}
} }
return Creator.CreateInstance<TFactory>(typeBuilder.CreateTypeInfo()!.AsType(), container);
} }
} }

@ -9,28 +9,27 @@ using System.Reflection;
using LightweightIocContainer.Exceptions; using LightweightIocContainer.Exceptions;
using LightweightIocContainer.Interfaces.Factories; using LightweightIocContainer.Interfaces.Factories;
namespace LightweightIocContainer.Factories namespace LightweightIocContainer.Factories;
/// <summary>
/// Base class for the <see cref="ITypedFactory"/>
/// </summary>
public abstract class TypedFactoryBase<TFactory> : ITypedFactory
{ {
/// <summary> /// <summary>
/// Base class for the <see cref="ITypedFactory"/> /// The create methods of this <see cref="ITypedFactory"/>
/// </summary> /// </summary>
public abstract class TypedFactoryBase<TFactory> : ITypedFactory public List<MethodInfo> CreateMethods
{ {
/// <summary> get
/// The create methods of this <see cref="ITypedFactory"/>
/// </summary>
public List<MethodInfo> CreateMethods
{ {
get Type factoryType = typeof(TFactory);
{
Type factoryType = typeof(TFactory);
List<MethodInfo> createMethods = factoryType.GetMethods().Where(m => m.ReturnType != typeof(void)).ToList(); List<MethodInfo> createMethods = factoryType.GetMethods().Where(m => m.ReturnType != typeof(void)).ToList();
if (!createMethods.Any()) if (!createMethods.Any())
throw new InvalidFactoryRegistrationException($"Factory {factoryType.Name} has no create methods."); throw new InvalidFactoryRegistrationException($"Factory {factoryType.Name} has no create methods.");
return createMethods; return createMethods;
}
} }
} }
} }

@ -6,53 +6,52 @@ using System;
using System.Reflection; using System.Reflection;
using LightweightIocContainer.Exceptions; using LightweightIocContainer.Exceptions;
namespace LightweightIocContainer namespace LightweightIocContainer;
/// <summary>
/// Helper class to call a generic method without generic type parameters
/// </summary>
internal static class GenericMethodCaller
{ {
/// <summary> /// <summary>
/// Helper class to call a generic method without generic type parameters /// Call a generic method without generic type parameters
/// </summary> /// </summary>
internal static class GenericMethodCaller /// <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="bindingFlags">The <see cref="BindingFlags"/> to find the method</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? Call(object caller, string functionName, Type genericParameter, BindingFlags bindingFlags, params object?[] parameters)
{ {
/// <summary> MethodInfo? method = caller.GetType().GetMethod(functionName, bindingFlags);
/// Call a generic method without generic type parameters MethodInfo? genericMethod = method?.MakeGenericMethod(genericParameter);
/// </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="bindingFlags">The <see cref="BindingFlags"/> to find the method</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? Call(object caller, string functionName, Type genericParameter, BindingFlags bindingFlags, params object?[] parameters)
{
MethodInfo? method = caller.GetType().GetMethod(functionName, bindingFlags);
MethodInfo? genericMethod = method?.MakeGenericMethod(genericParameter);
if (genericMethod == null) if (genericMethod == null)
throw new GenericMethodNotFoundException(functionName); throw new GenericMethodNotFoundException(functionName);
try //exceptions thrown by methods called with invoke are wrapped into another exception, the exception thrown by the invoked method can be returned by `Exception.GetBaseException()` try //exceptions thrown by methods called with invoke are wrapped into another exception, the exception thrown by the invoked method can be returned by `Exception.GetBaseException()`
{ {
return genericMethod.Invoke(caller, parameters); return genericMethod.Invoke(caller, parameters);
} }
catch (Exception ex) catch (Exception ex)
{ {
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);
} }
/// <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);
} }

@ -9,44 +9,43 @@ using LightweightIocContainer.Interfaces;
using LightweightIocContainer.Interfaces.Installers; using LightweightIocContainer.Interfaces.Installers;
using LightweightIocContainer.Interfaces.Registrations; using LightweightIocContainer.Interfaces.Registrations;
namespace LightweightIocContainer.Installers namespace LightweightIocContainer.Installers;
/// <summary>
/// An <see cref="IIocInstaller"/> that installs all <see cref="IIocInstaller"/>s for its given <see cref="Assembly"/>
/// </summary>
public class AssemblyInstaller : IAssemblyInstaller
{ {
/// <summary> /// <summary>
/// An <see cref="IIocInstaller"/> that installs all <see cref="IIocInstaller"/>s for its given <see cref="Assembly"/> /// An <see cref="IIocInstaller"/> that installs all <see cref="IIocInstaller"/>s for its given <see cref="Assembly"/>
/// </summary> /// </summary>
public class AssemblyInstaller : IAssemblyInstaller /// <param name="assembly">The <see cref="Assembly"/> from where the <see cref="IIocInstaller"/>s will be installed</param>
public AssemblyInstaller(Assembly assembly)
{ {
/// <summary> Installers = new List<IIocInstaller>();
/// An <see cref="IIocInstaller"/> that installs all <see cref="IIocInstaller"/>s for its given <see cref="Assembly"/>
/// </summary>
/// <param name="assembly">The <see cref="Assembly"/> from where the <see cref="IIocInstaller"/>s will be installed</param>
public AssemblyInstaller(Assembly assembly)
{
Installers = new List<IIocInstaller>();
Type[] types = assembly.GetTypes(); Type[] types = assembly.GetTypes();
foreach (Type type in types) foreach (Type type in types)
{ {
if (!typeof(IIocInstaller).IsAssignableFrom(type) || type.IsNestedPrivate) if (!typeof(IIocInstaller).IsAssignableFrom(type) || type.IsNestedPrivate)
continue; continue;
Installers.Add(Creator.CreateInstance<IIocInstaller>(type)); Installers.Add(Creator.CreateInstance<IIocInstaller>(type));
}
} }
}
/// <summary> /// <summary>
/// The <see cref="IIocInstaller"/>s of the Assembly that this <see cref="AssemblyInstaller"/> is installing /// The <see cref="IIocInstaller"/>s of the Assembly that this <see cref="AssemblyInstaller"/> is installing
/// </summary> /// </summary>
public List<IIocInstaller> Installers { get; } public List<IIocInstaller> Installers { get; }
/// <summary> /// <summary>
/// Install the found <see cref="IIocInstaller"/>s in the given <see cref="IIocContainer"/> /// Install the found <see cref="IIocInstaller"/>s in the given <see cref="IIocContainer"/>
/// </summary> /// </summary>
/// <param name="registration">The <see cref="IRegistrationCollector"/> where <see cref="IRegistration"/>s are added</param> /// <param name="registration">The <see cref="IRegistrationCollector"/> where <see cref="IRegistration"/>s are added</param>
public void Install(IRegistrationCollector registration) public void Install(IRegistrationCollector registration)
{ {
foreach (IIocInstaller installer in Installers) foreach (IIocInstaller installer in Installers)
installer.Install(registration); installer.Install(registration);
}
} }
} }

@ -5,28 +5,27 @@
using System.Reflection; using System.Reflection;
using LightweightIocContainer.Interfaces.Installers; using LightweightIocContainer.Interfaces.Installers;
namespace LightweightIocContainer.Installers namespace LightweightIocContainer.Installers;
/// <summary>
/// Helper class that supplies methods to find the wanted <see cref="Assembly"/>
/// </summary>
public static class FromAssembly
{ {
/// <summary> /// <summary>
/// Helper class that supplies methods to find the wanted <see cref="Assembly"/> /// Get an <see cref="IAssemblyInstaller"/> that installs from the <see cref="Assembly"/> calling the method
/// </summary> /// </summary>
public static class FromAssembly /// <returns>A new <see cref="IAssemblyInstaller"/> with the calling <see cref="Assembly"/></returns>
public static IAssemblyInstaller This()
{ {
/// <summary> Assembly assembly = Assembly.GetCallingAssembly();
/// Get an <see cref="IAssemblyInstaller"/> that installs from the <see cref="Assembly"/> calling the method return new AssemblyInstaller(assembly);
/// </summary>
/// <returns>A new <see cref="IAssemblyInstaller"/> with the calling <see cref="Assembly"/></returns>
public static IAssemblyInstaller This()
{
Assembly assembly = Assembly.GetCallingAssembly();
return new AssemblyInstaller(assembly);
}
/// <summary>
/// Get an <see cref="IAssemblyInstaller"/> that installs from the given <see cref="Assembly"/>
/// </summary>
/// <param name="assembly">The given <see cref="Assembly"/></param>
/// <returns>A new <see cref="IAssemblyInstaller"/> with the given <see cref="Assembly"/></returns>
public static IAssemblyInstaller Instance(Assembly assembly) => new AssemblyInstaller(assembly);
} }
/// <summary>
/// Get an <see cref="IAssemblyInstaller"/> that installs from the given <see cref="Assembly"/>
/// </summary>
/// <param name="assembly">The given <see cref="Assembly"/></param>
/// <returns>A new <see cref="IAssemblyInstaller"/> with the given <see cref="Assembly"/></returns>
public static IAssemblyInstaller Instance(Assembly assembly) => new AssemblyInstaller(assembly);
} }

@ -5,28 +5,27 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Reflection; using System.Reflection;
namespace LightweightIocContainer.Interfaces.Factories namespace LightweightIocContainer.Interfaces.Factories;
/// <summary>
/// Non-generic <see cref="ITypedFactory{TFactory}"/>
/// </summary>
public interface ITypedFactory
{ {
/// <summary> /// <summary>
/// Non-generic <see cref="ITypedFactory{TFactory}"/> /// The create methods of this <see cref="ITypedFactory"/>
/// </summary> /// </summary>
public interface ITypedFactory List<MethodInfo> CreateMethods { get; }
{ }
/// <summary>
/// The create methods of this <see cref="ITypedFactory"/>
/// </summary>
List<MethodInfo> CreateMethods { get; }
}
/// <summary>
/// Class to help implement an abstract typed factory
/// </summary>
/// <typeparam name="TFactory">The type of the abstract factory</typeparam>
public interface ITypedFactory<TFactory> : ITypedFactory
{
/// <summary> /// <summary>
/// Class to help implement an abstract typed factory /// The implemented abstract typed factory
/// </summary> /// </summary>
/// <typeparam name="TFactory">The type of the abstract factory</typeparam> TFactory Factory { get; set; }
public interface ITypedFactory<TFactory> : ITypedFactory
{
/// <summary>
/// The implemented abstract typed factory
/// </summary>
TFactory Factory { get; set; }
}
} }

@ -6,37 +6,36 @@ using System;
using LightweightIocContainer.Interfaces.Installers; using LightweightIocContainer.Interfaces.Installers;
using LightweightIocContainer.Interfaces.Registrations; using LightweightIocContainer.Interfaces.Registrations;
namespace LightweightIocContainer.Interfaces namespace LightweightIocContainer.Interfaces;
/// <summary>
/// The main container that carries all <see cref="IRegistration"/>s
/// </summary>
public interface IIocContainer : IDisposable
{ {
/// <summary> /// <summary>
/// The main container that carries all <see cref="IRegistration"/>s /// Install the given installers for the current <see cref="IIocContainer"/>
/// </summary> /// </summary>
public interface IIocContainer : IDisposable /// <param name="installers">The given <see cref="IIocInstaller"/>s</param>
{ /// <returns>An instance of the current <see cref="IIocContainer"/></returns>
/// <summary> IIocContainer Install(params IIocInstaller[] installers);
/// Install the given installers for the current <see cref="IIocContainer"/>
/// </summary>
/// <param name="installers">The given <see cref="IIocInstaller"/>s</param>
/// <returns>An instance of the current <see cref="IIocContainer"/></returns>
IIocContainer Install(params IIocInstaller[] installers);
/// <summary> /// <summary>
/// Register an <see cref="IRegistration"/> at this <see cref="IocContainer"/> /// Register an <see cref="IRegistration"/> at this <see cref="IocContainer"/>
/// </summary> /// </summary>
/// <param name="addRegistration">The <see cref="Func{T, TResult}"/> that creates an <see cref="IRegistration"/></param> /// <param name="addRegistration">The <see cref="Func{T, TResult}"/> that creates an <see cref="IRegistration"/></param>
public void Register(Func<IRegistrationCollector, IRegistration> addRegistration); public void Register(Func<IRegistrationCollector, IRegistration> addRegistration);
/// <summary> /// <summary>
/// Clear the multiton instances of the given <see cref="Type"/> from the registered multitons list /// Clear the multiton instances of the given <see cref="Type"/> from the registered multitons list
/// </summary> /// </summary>
/// <typeparam name="T">The <see cref="Type"/> to clear the multiton instances</typeparam> /// <typeparam name="T">The <see cref="Type"/> to clear the multiton instances</typeparam>
void ClearMultitonInstances<T>(); void ClearMultitonInstances<T>();
/// <summary> /// <summary>
/// Is the given <see cref="Type"/> registered with this <see cref="IIocContainer"/> /// Is the given <see cref="Type"/> registered with this <see cref="IIocContainer"/>
/// </summary> /// </summary>
/// <typeparam name="T">The given <see cref="Type"/></typeparam> /// <typeparam name="T">The given <see cref="Type"/></typeparam>
/// <returns>True if the given <see cref="Type"/> is registered with this <see cref="IIocContainer"/>, false if not</returns> /// <returns>True if the given <see cref="Type"/> is registered with this <see cref="IIocContainer"/>, false if not</returns>
bool IsTypeRegistered<T>(); bool IsTypeRegistered<T>();
}
} }

@ -4,26 +4,25 @@
using System; using System;
namespace LightweightIocContainer.Interfaces namespace LightweightIocContainer.Interfaces;
/// <summary>
/// Provides <see cref="Resolve{T}()"/> methods
/// </summary>
public interface IIocResolver : IDisposable
{ {
/// <summary> /// <summary>
/// Provides <see cref="Resolve{T}()"/> methods /// Gets an instance of the given <see cref="Type"/>
/// </summary> /// </summary>
public interface IIocResolver : IDisposable /// <typeparam name="T">The given <see cref="Type"/></typeparam>
{ /// <returns>An instance of the given <see cref="Type"/></returns>
/// <summary> T Resolve<T>();
/// Gets an instance of the given <see cref="Type"/>
/// </summary>
/// <typeparam name="T">The given <see cref="Type"/></typeparam>
/// <returns>An instance of the given <see cref="Type"/></returns>
T Resolve<T>();
/// <summary> /// <summary>
/// Gets an instance of the given <see cref="Type"/> /// Gets an instance of the given <see cref="Type"/>
/// </summary> /// </summary>
/// <typeparam name="T">The given <see cref="Type"/></typeparam> /// <typeparam name="T">The given <see cref="Type"/></typeparam>
/// <param name="arguments">The constructor arguments</param> /// <param name="arguments">The constructor arguments</param>
/// <returns>An instance of the given <see cref="Type"/></returns> /// <returns>An instance of the given <see cref="Type"/></returns>
T Resolve<T>(params object[] arguments); T Resolve<T>(params object[] arguments);
}
} }

@ -5,16 +5,15 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Reflection; using System.Reflection;
namespace LightweightIocContainer.Interfaces.Installers namespace LightweightIocContainer.Interfaces.Installers;
/// <summary>
/// An <see cref="IIocInstaller"/> that installs all <see cref="IIocInstaller"/>s for its given <see cref="Assembly"/>
/// </summary>
public interface IAssemblyInstaller : IIocInstaller
{ {
/// <summary> /// <summary>
/// An <see cref="IIocInstaller"/> that installs all <see cref="IIocInstaller"/>s for its given <see cref="Assembly"/> /// The <see cref="IIocInstaller"/>s of the <see cref="Assembly"/> that this <see cref="IAssemblyInstaller"/> is installing
/// </summary> /// </summary>
public interface IAssemblyInstaller : IIocInstaller List<IIocInstaller> Installers { get; }
{
/// <summary>
/// The <see cref="IIocInstaller"/>s of the <see cref="Assembly"/> that this <see cref="IAssemblyInstaller"/> is installing
/// </summary>
List<IIocInstaller> Installers { get; }
}
} }

@ -4,17 +4,16 @@
using LightweightIocContainer.Interfaces.Registrations; using LightweightIocContainer.Interfaces.Registrations;
namespace LightweightIocContainer.Interfaces.Installers namespace LightweightIocContainer.Interfaces.Installers;
/// <summary>
/// The base class for <see cref="IIocContainer"/> installers
/// </summary>
public interface IIocInstaller
{ {
/// <summary> /// <summary>
/// The base class for <see cref="IIocContainer"/> installers /// Install the needed <see cref="IRegistration"/>s in the given <see cref="IIocContainer"/>
/// </summary> /// </summary>
public interface IIocInstaller /// <param name="registration">The <see cref="IRegistrationCollector"/> where <see cref="IRegistration"/>s are added</param>
{ void Install(IRegistrationCollector registration);
/// <summary>
/// Install the needed <see cref="IRegistration"/>s in the given <see cref="IIocContainer"/>
/// </summary>
/// <param name="registration">The <see cref="IRegistrationCollector"/> where <see cref="IRegistration"/>s are added</param>
void Install(IRegistrationCollector registration);
}
} }

@ -5,32 +5,31 @@
using System; using System;
using LightweightIocContainer.Interfaces.Installers; using LightweightIocContainer.Interfaces.Installers;
namespace LightweightIocContainer.Interfaces.Registrations.Fluent namespace LightweightIocContainer.Interfaces.Registrations.Fluent;
/// <summary>
/// Provides an <see cref="OnCreateAction"/> to the generic <see cref="IOnCreate{TInterface, TImplementation}"/>
/// </summary>
public interface IOnCreate
{ {
/// <summary> /// <summary>
/// Provides an <see cref="OnCreateAction"/> to the generic <see cref="IOnCreate{TInterface, TImplementation}"/> /// This <see cref="Action"/> is invoked when an instance of this type is created.
/// <para>Can be set in the <see cref="IIocInstaller"/> by calling <see cref="IOnCreate{TInterface, TImplementation}.OnCreate"/></para>
/// </summary> /// </summary>
public interface IOnCreate internal Action<object?>? OnCreateAction { get; }
{ }
/// <summary>
/// This <see cref="Action"/> is invoked when an instance of this type is created.
/// <para>Can be set in the <see cref="IIocInstaller"/> by calling <see cref="IOnCreate{TInterface, TImplementation}.OnCreate"/></para>
/// </summary>
internal Action<object?>? OnCreateAction { get; }
}
/// <summary>
/// Provides an <see cref="OnCreate"/> method to an <see cref="IRegistrationBase"/>
/// </summary>
/// <typeparam name="TInterface">The registered interface</typeparam>
/// <typeparam name="TImplementation">The registered implementation</typeparam>
public interface IOnCreate<TInterface, TImplementation> : IOnCreate where TImplementation : TInterface
{
/// <summary> /// <summary>
/// Provides an <see cref="OnCreate"/> method to an <see cref="IRegistrationBase"/> /// Pass an <see cref="Action{T}"/> that will be invoked when an instance of this type is created
/// </summary> /// </summary>
/// <typeparam name="TInterface">The registered interface</typeparam> /// <param name="action">The <see cref="Action{T}"/></param>
/// <typeparam name="TImplementation">The registered implementation</typeparam> /// <returns>The current instance of this <see cref="ITypedRegistration{TInterface,TImplementation}"/></returns>
public interface IOnCreate<TInterface, TImplementation> : IOnCreate where TImplementation : TInterface ITypedRegistration<TInterface, TImplementation> OnCreate(Action<TImplementation?> action);
{
/// <summary>
/// Pass an <see cref="Action{T}"/> that will be invoked when an instance of this type is created
/// </summary>
/// <param name="action">The <see cref="Action{T}"/></param>
/// <returns>The current instance of this <see cref="ITypedRegistration{TInterface,TImplementation}"/></returns>
ITypedRegistration<TInterface, TImplementation> OnCreate(Action<TImplementation?> action);
}
} }

@ -4,34 +4,33 @@
using LightweightIocContainer.Interfaces.Factories; using LightweightIocContainer.Interfaces.Factories;
namespace LightweightIocContainer.Interfaces.Registrations.Fluent namespace LightweightIocContainer.Interfaces.Registrations.Fluent;
/// <summary>
/// Provides a <see cref="WithFactory{TFactory}"/> method to an <see cref="IRegistrationBase"/>
/// </summary>
public interface IWithFactory
{ {
/// <summary> /// <summary>
/// Provides a <see cref="WithFactory{TFactory}"/> method to an <see cref="IRegistrationBase"/> /// Register an abstract typed factory for the <see cref="IRegistrationBase"/>
/// </summary> /// </summary>
public interface IWithFactory /// <typeparam name="TFactory">The type of the abstract typed factory</typeparam>
{ /// <returns>The current instance of this <see cref="IRegistrationBase"/></returns>
/// <summary> IRegistrationBase WithFactory<TFactory>();
/// Register an abstract typed factory for the <see cref="IRegistrationBase"/>
/// </summary>
/// <typeparam name="TFactory">The type of the abstract typed factory</typeparam>
/// <returns>The current instance of this <see cref="IRegistrationBase"/></returns>
IRegistrationBase WithFactory<TFactory>();
/// <summary> /// <summary>
/// Register a custom implemented factory for the <see cref="IRegistrationBase"/> /// Register a custom implemented factory for the <see cref="IRegistrationBase"/>
/// </summary> /// </summary>
/// <typeparam name="TFactoryInterface">The type of the interface for the custom factory</typeparam> /// <typeparam name="TFactoryInterface">The type of the interface for the custom factory</typeparam>
/// <typeparam name="TFactoryImplementation">The type of the implementation for the custom factory</typeparam> /// <typeparam name="TFactoryImplementation">The type of the implementation for the custom factory</typeparam>
/// <returns>The current instance of this <see cref="IRegistrationBase"/></returns> /// <returns>The current instance of this <see cref="IRegistrationBase"/></returns>
IRegistrationBase WithFactory<TFactoryInterface, TFactoryImplementation>() where TFactoryImplementation : TFactoryInterface; IRegistrationBase WithFactory<TFactoryInterface, TFactoryImplementation>() where TFactoryImplementation : TFactoryInterface;
} }
internal interface IWithFactoryInternal : IWithFactory internal interface IWithFactoryInternal : IWithFactory
{ {
/// <summary> /// <summary>
/// The Factory added with the <see cref="IWithFactory.WithFactory{TFactory}"/> method /// The Factory added with the <see cref="IWithFactory.WithFactory{TFactory}"/> method
/// </summary> /// </summary>
ITypedFactory? Factory { get; } ITypedFactory? Factory { get; }
}
} }

@ -6,38 +6,37 @@ using System;
using LightweightIocContainer.Exceptions; using LightweightIocContainer.Exceptions;
using LightweightIocContainer.Interfaces.Installers; using LightweightIocContainer.Interfaces.Installers;
namespace LightweightIocContainer.Interfaces.Registrations.Fluent namespace LightweightIocContainer.Interfaces.Registrations.Fluent;
/// <summary>
/// Provides a <see cref="WithParameters(object[])"/> method to an <see cref="IRegistration"/>
/// </summary>
public interface IWithParameters
{ {
/// <summary> /// <summary>
/// Provides a <see cref="WithParameters(object[])"/> method to an <see cref="IRegistration"/> /// Pass parameters that will be used to<see cref="IocContainer.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> /// </summary>
public interface IWithParameters /// <param name="parameters">The parameters</param>
{ /// <returns>The current instance of this <see cref="IRegistrationBase"/></returns>
/// <summary> /// <exception cref="InvalidRegistrationException"><see cref="IWithParametersInternal.Parameters"/> are already set or no parameters given</exception>
/// Pass parameters that will be used to<see cref="IocContainer.Resolve{T}()"/> an instance of this <see cref="IRegistration.InterfaceType"/> IRegistrationBase WithParameters(params object[] parameters);
/// <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"/></returns>
/// <exception cref="InvalidRegistrationException"><see cref="IWithParametersInternal.Parameters"/> are already set or no parameters given</exception>
IRegistrationBase WithParameters(params object[] parameters);
/// <summary> /// <summary>
/// Pass parameters that will be used to<see cref="IocContainer.Resolve{T}()"/> an instance of this <see cref="IRegistration.InterfaceType"/> /// Pass parameters that will be used to<see cref="IocContainer.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> /// <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> /// </summary>
/// <param name="parameters">The parameters with their position</param> /// <param name="parameters">The parameters with their position</param>
/// <returns>The current instance of this <see cref="IRegistrationBase"/></returns> /// <returns>The current instance of this <see cref="IRegistrationBase"/></returns>
/// <exception cref="InvalidRegistrationException"><see cref="IWithParametersInternal.Parameters"/> are already set or no parameters given</exception> /// <exception cref="InvalidRegistrationException"><see cref="IWithParametersInternal.Parameters"/> are already set or no parameters given</exception>
IRegistrationBase WithParameters(params (int index, object parameter)[] parameters); IRegistrationBase WithParameters(params (int index, object parameter)[] parameters);
} }
internal interface IWithParametersInternal : IWithParameters internal interface IWithParametersInternal : IWithParameters
{ {
/// <summary> /// <summary>
/// An <see cref="Array"/> of parameters that are used to <see cref="IocContainer.Resolve{T}()"/> an instance of this <see cref="IRegistration.InterfaceType"/> /// An <see cref="Array"/> of parameters that are used to <see cref="IocContainer.Resolve{T}()"/> an instance of this <see cref="IRegistration.InterfaceType"/>
/// <para>Can be set in the <see cref="IIocInstaller"/> by calling <see cref="IWithParameters.WithParameters(object[])"/></para> /// <para>Can be set in the <see cref="IIocInstaller"/> by calling <see cref="IWithParameters.WithParameters(object[])"/></para>
/// </summary> /// </summary>
object[]? Parameters { get; } object[]? Parameters { get; }
}
} }

@ -2,16 +2,15 @@
// // Created: 2020-01-29 // // Created: 2020-01-29
// // Copyright(c) 2020 SimonG. All Rights Reserved. // // Copyright(c) 2020 SimonG. All Rights Reserved.
namespace LightweightIocContainer.Interfaces.Registrations namespace LightweightIocContainer.Interfaces.Registrations;
/// <summary>
/// Provides a <see cref="LightweightIocContainer.Lifestyle"/> to an <see cref="IRegistration"/>
/// </summary>
public interface ILifestyleProvider
{ {
/// <summary> /// <summary>
/// Provides a <see cref="LightweightIocContainer.Lifestyle"/> to an <see cref="IRegistration"/> /// The Lifestyle of Instances that are created with this <see cref="IRegistration"/>
/// </summary> /// </summary>
public interface ILifestyleProvider Lifestyle Lifestyle { get; }
{
/// <summary>
/// The Lifestyle of Instances that are created with this <see cref="IRegistration"/>
/// </summary>
Lifestyle Lifestyle { get; }
}
} }

@ -2,16 +2,15 @@
// Created: 2020-11-19 // Created: 2020-11-19
// Copyright(c) 2020 SimonG. All Rights Reserved. // Copyright(c) 2020 SimonG. All Rights Reserved.
namespace LightweightIocContainer.Interfaces.Registrations namespace LightweightIocContainer.Interfaces.Registrations;
/// <summary>
/// An <see cref="IRegistration"/> to register multiple interfaces for on implementation type that implements them as a multiton
/// </summary>
/// <typeparam name="TInterface1">The first interface</typeparam>
/// <typeparam name="TInterface2">The second interface</typeparam>
/// <typeparam name="TImplementation">The implementation</typeparam>
public interface IMultipleMultitonRegistration<TInterface1, TInterface2, TImplementation> : IMultitonRegistration<TInterface1, TImplementation>, IMultipleRegistration<TInterface1, TInterface2, TImplementation> where TImplementation : TInterface1, TInterface2
{ {
/// <summary>
/// An <see cref="IRegistration"/> to register multiple interfaces for on implementation type that implements them as a multiton
/// </summary>
/// <typeparam name="TInterface1">The first interface</typeparam>
/// <typeparam name="TInterface2">The second interface</typeparam>
/// <typeparam name="TImplementation">The implementation</typeparam>
public interface IMultipleMultitonRegistration<TInterface1, TInterface2, TImplementation> : IMultitonRegistration<TInterface1, TImplementation>, IMultipleRegistration<TInterface1, TInterface2, TImplementation> where TImplementation : TInterface1, TInterface2
{
}
} }

@ -4,68 +4,67 @@
using System.Collections.Generic; using System.Collections.Generic;
namespace LightweightIocContainer.Interfaces.Registrations namespace LightweightIocContainer.Interfaces.Registrations;
/// <summary>
/// The base interface for every <see cref="IMultipleRegistration{TInterface1,TInterface2,TImplementation}"/> to register multiple interfaces
/// </summary>
/// <typeparam name="TInterface1">The first interface</typeparam>
/// <typeparam name="TImplementation">The implementation</typeparam>
public interface IMultipleRegistration<TInterface1, TImplementation> : ITypedRegistration<TInterface1, TImplementation> where TImplementation : TInterface1
{ {
/// <summary> /// <summary>
/// The base interface for every <see cref="IMultipleRegistration{TInterface1,TInterface2,TImplementation}"/> to register multiple interfaces /// A <see cref="List{T}"/> of <see cref="IRegistration"/>s that are registered within this <see cref="IMultipleRegistration{TInterface1,TImplementation}"/>
/// </summary> /// </summary>
/// <typeparam name="TInterface1">The first interface</typeparam> List<IRegistration> Registrations { get; }
/// <typeparam name="TImplementation">The implementation</typeparam> }
public interface IMultipleRegistration<TInterface1, TImplementation> : ITypedRegistration<TInterface1, TImplementation> where TImplementation : TInterface1
{
/// <summary>
/// A <see cref="List{T}"/> of <see cref="IRegistration"/>s that are registered within this <see cref="IMultipleRegistration{TInterface1,TImplementation}"/>
/// </summary>
List<IRegistration> Registrations { get; }
}
/// <summary> /// <summary>
/// An <see cref="IRegistration"/> to register multiple interfaces for on implementation type /// An <see cref="IRegistration"/> to register multiple interfaces for on implementation type
/// </summary> /// </summary>
/// <typeparam name="TInterface1">The first interface</typeparam> /// <typeparam name="TInterface1">The first interface</typeparam>
/// <typeparam name="TInterface2">The second interface</typeparam> /// <typeparam name="TInterface2">The second interface</typeparam>
/// <typeparam name="TImplementation">The implementation</typeparam> /// <typeparam name="TImplementation">The implementation</typeparam>
public interface IMultipleRegistration<TInterface1, TInterface2, TImplementation> : IMultipleRegistration<TInterface1, TImplementation> where TImplementation : TInterface1, TInterface2 public interface IMultipleRegistration<TInterface1, TInterface2, TImplementation> : IMultipleRegistration<TInterface1, TImplementation> where TImplementation : TInterface1, TInterface2
{ {
} }
/// <summary> /// <summary>
/// An <see cref="IRegistration"/> to register multiple interfaces for on implementation type /// An <see cref="IRegistration"/> to register multiple interfaces for on implementation type
/// </summary> /// </summary>
/// <typeparam name="TInterface1">The first interface</typeparam> /// <typeparam name="TInterface1">The first interface</typeparam>
/// <typeparam name="TInterface2">The second interface</typeparam> /// <typeparam name="TInterface2">The second interface</typeparam>
/// <typeparam name="TInterface3">The third interface</typeparam> /// <typeparam name="TInterface3">The third interface</typeparam>
/// <typeparam name="TImplementation">The implementation</typeparam> /// <typeparam name="TImplementation">The implementation</typeparam>
public interface IMultipleRegistration<TInterface1, TInterface2, TInterface3, TImplementation> : IMultipleRegistration<TInterface1, TImplementation> where TImplementation : TInterface1, TInterface2, TInterface3 public interface IMultipleRegistration<TInterface1, TInterface2, TInterface3, TImplementation> : IMultipleRegistration<TInterface1, TImplementation> where TImplementation : TInterface1, TInterface2, TInterface3
{ {
} }
/// <summary> /// <summary>
/// An <see cref="IRegistration"/> to register multiple interfaces for on implementation type /// An <see cref="IRegistration"/> to register multiple interfaces for on implementation type
/// </summary> /// </summary>
/// <typeparam name="TInterface1">The first interface</typeparam> /// <typeparam name="TInterface1">The first interface</typeparam>
/// <typeparam name="TInterface2">The second interface</typeparam> /// <typeparam name="TInterface2">The second interface</typeparam>
/// <typeparam name="TInterface3">The third interface</typeparam> /// <typeparam name="TInterface3">The third interface</typeparam>
/// <typeparam name="TInterface4">The fourth interface</typeparam> /// <typeparam name="TInterface4">The fourth interface</typeparam>
/// <typeparam name="TImplementation">The implementation</typeparam> /// <typeparam name="TImplementation">The implementation</typeparam>
public interface IMultipleRegistration<TInterface1, TInterface2, TInterface3, TInterface4, TImplementation> : IMultipleRegistration<TInterface1, TImplementation> where TImplementation : TInterface1, TInterface2, TInterface3, TInterface4 public interface IMultipleRegistration<TInterface1, TInterface2, TInterface3, TInterface4, TImplementation> : IMultipleRegistration<TInterface1, TImplementation> where TImplementation : TInterface1, TInterface2, TInterface3, TInterface4
{ {
} }
/// <summary> /// <summary>
/// An <see cref="IRegistration"/> to register multiple interfaces for on implementation type /// An <see cref="IRegistration"/> to register multiple interfaces for on implementation type
/// </summary> /// </summary>
/// <typeparam name="TInterface1">The first interface</typeparam> /// <typeparam name="TInterface1">The first interface</typeparam>
/// <typeparam name="TInterface2">The second interface</typeparam> /// <typeparam name="TInterface2">The second interface</typeparam>
/// <typeparam name="TInterface3">The third interface</typeparam> /// <typeparam name="TInterface3">The third interface</typeparam>
/// <typeparam name="TInterface4">The fourth interface</typeparam> /// <typeparam name="TInterface4">The fourth interface</typeparam>
/// <typeparam name="TInterface5">The fifth interface</typeparam> /// <typeparam name="TInterface5">The fifth interface</typeparam>
/// <typeparam name="TImplementation">The implementation</typeparam> /// <typeparam name="TImplementation">The implementation</typeparam>
public interface IMultipleRegistration<TInterface1, TInterface2, TInterface3, TInterface4, TInterface5, TImplementation> : IMultipleRegistration<TInterface1, TImplementation> where TImplementation : TInterface1, TInterface2, TInterface3, TInterface4, TInterface5 public interface IMultipleRegistration<TInterface1, TInterface2, TInterface3, TInterface4, TInterface5, TImplementation> : IMultipleRegistration<TInterface1, TImplementation> where TImplementation : TInterface1, TInterface2, TInterface3, TInterface4, TInterface5
{ {
}
} }

@ -4,26 +4,25 @@
using System; using System;
namespace LightweightIocContainer.Interfaces.Registrations namespace LightweightIocContainer.Interfaces.Registrations;
/// <summary>
/// Non generic <see cref="IMultipleRegistration{TInterface1,TImplementation}"/>
/// </summary>
public interface IMultitonRegistration : ITypedRegistration
{ {
/// <summary> /// <summary>
/// Non generic <see cref="IMultipleRegistration{TInterface1,TImplementation}"/> /// The <see cref="Type"/> of the multiton scope
/// </summary> /// </summary>
public interface IMultitonRegistration : ITypedRegistration Type Scope { get; }
{ }
/// <summary>
/// The <see cref="Type"/> of the multiton scope
/// </summary>
Type Scope { get; }
}
/// <summary> /// <summary>
/// The registration that is used to register a multiton /// The registration that is used to register a multiton
/// </summary> /// </summary>
/// <typeparam name="TInterface">The registered interface</typeparam> /// <typeparam name="TInterface">The registered interface</typeparam>
/// <typeparam name="TImplementation">The registered implementation</typeparam> /// <typeparam name="TImplementation">The registered implementation</typeparam>
public interface IMultitonRegistration<TInterface, TImplementation> : IMultitonRegistration, ITypedRegistration<TInterface, TImplementation> where TImplementation : TInterface public interface IMultitonRegistration<TInterface, TImplementation> : IMultitonRegistration, ITypedRegistration<TInterface, TImplementation> where TImplementation : TInterface
{ {
}
} }

@ -2,13 +2,12 @@
// Created: 2020-09-18 // Created: 2020-09-18
// Copyright(c) 2020 SimonG. All Rights Reserved. // Copyright(c) 2020 SimonG. All Rights Reserved.
namespace LightweightIocContainer.Interfaces.Registrations namespace LightweightIocContainer.Interfaces.Registrations;
/// <summary>
/// <see cref="IRegistration"/> for open generic types
/// </summary>
public interface IOpenGenericRegistration : ITypedRegistration
{ {
/// <summary>
/// <see cref="IRegistration"/> for open generic types
/// </summary>
public interface IOpenGenericRegistration : ITypedRegistration
{
}
} }

@ -4,16 +4,15 @@
using System; using System;
namespace LightweightIocContainer.Interfaces.Registrations namespace LightweightIocContainer.Interfaces.Registrations;
/// <summary>
/// The base registration that is used to register an Interface
/// </summary>
public interface IRegistration
{ {
/// <summary> /// <summary>
/// The base registration that is used to register an Interface /// The <see cref="Type"/> of the Interface that is registered with this <see cref="IRegistration"/>
/// </summary> /// </summary>
public interface IRegistration Type InterfaceType { get; }
{
/// <summary>
/// The <see cref="Type"/> of the Interface that is registered with this <see cref="IRegistration"/>
/// </summary>
Type InterfaceType { get; }
}
} }

@ -4,13 +4,12 @@
using LightweightIocContainer.Interfaces.Registrations.Fluent; using LightweightIocContainer.Interfaces.Registrations.Fluent;
namespace LightweightIocContainer.Interfaces.Registrations namespace LightweightIocContainer.Interfaces.Registrations;
/// <summary>
/// The <see cref="IRegistrationBase"/> that is used to register an Interface and extends the <see cref="IRegistration"/> with fluent options
/// </summary>
public interface IRegistrationBase : IRegistration, IWithFactory, IWithParameters, IWithDisposeStrategy
{ {
/// <summary>
/// The <see cref="IRegistrationBase"/> that is used to register an Interface and extends the <see cref="IRegistration"/> with fluent options
/// </summary>
public interface IRegistrationBase : IRegistration, IWithFactory, IWithParameters, IWithDisposeStrategy
{
}
} }

@ -4,24 +4,23 @@
using System; using System;
namespace LightweightIocContainer.Interfaces.Registrations namespace LightweightIocContainer.Interfaces.Registrations;
/// <summary>
/// The <see cref="IRegistration"/> to register either only an interface or only a <see cref="Type"/>
/// </summary>
/// <typeparam name="T">The <see cref="Type"/> of the <see cref="IRegistration"/></typeparam>
public interface ISingleTypeRegistration<T> : IRegistrationBase
{ {
/// <summary> /// <summary>
/// The <see cref="IRegistration"/> to register either only an interface or only a <see cref="Type"/> /// <see cref="Func{T,TResult}"/> that is invoked instead of creating an instance of this <see cref="Type"/> the default way
/// </summary> /// </summary>
/// <typeparam name="T">The <see cref="Type"/> of the <see cref="IRegistration"/></typeparam> Func<IIocResolver, T>? FactoryMethod { get; }
public interface ISingleTypeRegistration<T> : IRegistrationBase
{
/// <summary>
/// <see cref="Func{T,TResult}"/> that is invoked instead of creating an instance of this <see cref="Type"/> the default way
/// </summary>
Func<IIocResolver, T>? FactoryMethod { get; }
/// <summary> /// <summary>
/// Pass a <see cref="Func{T,TResult}"/> that will be invoked instead of creating an instance of this <see cref="Type"/> the default way /// Pass a <see cref="Func{T,TResult}"/> that will be invoked instead of creating an instance of this <see cref="Type"/> the default way
/// </summary> /// </summary>
/// <param name="factoryMethod">The <see cref="Func{T,TResult}"/></param> /// <param name="factoryMethod">The <see cref="Func{T,TResult}"/></param>
/// <returns>The current instance of this <see cref="IRegistration"/></returns> /// <returns>The current instance of this <see cref="IRegistration"/></returns>
ISingleTypeRegistration<T> WithFactoryMethod(Func<IIocResolver, T> factoryMethod); ISingleTypeRegistration<T> WithFactoryMethod(Func<IIocResolver, T> factoryMethod);
}
} }

@ -4,17 +4,16 @@
using LightweightIocContainer.Interfaces.Factories; using LightweightIocContainer.Interfaces.Factories;
namespace LightweightIocContainer.Interfaces.Registrations namespace LightweightIocContainer.Interfaces.Registrations;
/// <summary>
/// The registration that is used to register an abstract typed factory
/// </summary>
/// <typeparam name="TFactory">The type of the abstract typed factory</typeparam>
public interface ITypedFactoryRegistration<TFactory> : IRegistration
{ {
/// <summary> /// <summary>
/// The registration that is used to register an abstract typed factory /// The class that contains the implemented abstract factory of this <see cref="ITypedFactoryRegistration{TFactory}"/>
/// </summary> /// </summary>
/// <typeparam name="TFactory">The type of the abstract typed factory</typeparam> ITypedFactory<TFactory> Factory { get; }
public interface ITypedFactoryRegistration<TFactory> : IRegistration
{
/// <summary>
/// The class that contains the implemented abstract factory of this <see cref="ITypedFactoryRegistration{TFactory}"/>
/// </summary>
ITypedFactory<TFactory> Factory { get; }
}
} }

@ -5,24 +5,23 @@
using System; using System;
using LightweightIocContainer.Interfaces.Registrations.Fluent; using LightweightIocContainer.Interfaces.Registrations.Fluent;
namespace LightweightIocContainer.Interfaces.Registrations namespace LightweightIocContainer.Interfaces.Registrations;
/// <summary>
/// A base <see cref="ITypedRegistration"/> without generic interface and implementation
/// </summary>
public interface ITypedRegistration : IRegistrationBase
{ {
/// <summary> /// <summary>
/// A base <see cref="ITypedRegistration"/> without generic interface and implementation /// The <see cref="Type"/> that implements the <see cref="IRegistration.InterfaceType"/> that is registered with this <see cref="IRegistration"/>
/// </summary> /// </summary>
public interface ITypedRegistration : IRegistrationBase Type ImplementationType { get; }
{ }
/// <summary>
/// The <see cref="Type"/> that implements the <see cref="IRegistration.InterfaceType"/> that is registered with this <see cref="IRegistration"/>
/// </summary>
Type ImplementationType { get; }
}
/// <summary> /// <summary>
/// A <see cref="IRegistration"/> that implements a <see cref="Type"/> /// A <see cref="IRegistration"/> that implements a <see cref="Type"/>
/// </summary> /// </summary>
public interface ITypedRegistration<TInterface, TImplementation> : ITypedRegistration, IOnCreate<TInterface, TImplementation> where TImplementation : TInterface public interface ITypedRegistration<TInterface, TImplementation> : ITypedRegistration, IOnCreate<TInterface, TImplementation> where TImplementation : TInterface
{ {
}
} }

File diff suppressed because it is too large Load Diff

@ -4,26 +4,25 @@
using LightweightIocContainer.Interfaces.Registrations; using LightweightIocContainer.Interfaces.Registrations;
namespace LightweightIocContainer namespace LightweightIocContainer;
/// <summary>
/// The Lifestyles that can be used for a <see cref="IRegistrationBase"/>
/// </summary>
public enum Lifestyle
{ {
/// <summary> /// <summary>
/// The Lifestyles that can be used for a <see cref="IRegistrationBase"/> /// A new instance gets created every time an instance is resolved
/// </summary> /// </summary>
public enum Lifestyle Transient,
{
/// <summary>
/// A new instance gets created every time an instance is resolved
/// </summary>
Transient,
/// <summary> /// <summary>
/// One instance is created that gets returned every time an instance is resolved /// One instance is created that gets returned every time an instance is resolved
/// </summary> /// </summary>
Singleton, Singleton,
/// <summary> /// <summary>
/// A new instance gets created if the given scope has no created instance yet. Otherwise the already created instance is used. /// A new instance gets created if the given scope has no created instance yet. Otherwise the already created instance is used.
/// </summary> /// </summary>
Multiton Multiton
}
} }

@ -7,55 +7,54 @@ using System.Collections.Generic;
using LightweightIocContainer.Interfaces; using LightweightIocContainer.Interfaces;
using LightweightIocContainer.Interfaces.Registrations; using LightweightIocContainer.Interfaces.Registrations;
namespace LightweightIocContainer.Registrations namespace LightweightIocContainer.Registrations;
/// <summary>
/// An <see cref="IRegistrationBase"/> to register multiple interfaces for on implementation type that implements them as a multiton
/// </summary>
/// <typeparam name="TInterface1">The first interface</typeparam>
/// <typeparam name="TInterface2">The second interface</typeparam>
/// <typeparam name="TImplementation">The implementation</typeparam>
internal class MultipleMultitonRegistration<TInterface1, TInterface2, TImplementation> : MultitonRegistration<TInterface1, TImplementation>, IMultipleMultitonRegistration<TInterface1, TInterface2, TImplementation> where TImplementation : TInterface1, TInterface2
{ {
/// <summary> /// <summary>
/// An <see cref="IRegistrationBase"/> to register multiple interfaces for on implementation type that implements them as a multiton /// An <see cref="IRegistrationBase"/> to register multiple interfaces for on implementation type that implements them as a multiton
/// </summary> /// </summary>
/// <typeparam name="TInterface1">The first interface</typeparam> /// <param name="interfaceType1">The <see cref="Type"/> of the first interface</param>
/// <typeparam name="TInterface2">The second interface</typeparam> /// <param name="interfaceType2">The <see cref="Type"/> of the second interface</param>
/// <typeparam name="TImplementation">The implementation</typeparam> /// <param name="implementationType">The <see cref="Type"/> of the implementation</param>
internal class MultipleMultitonRegistration<TInterface1, TInterface2, TImplementation> : MultitonRegistration<TInterface1, TImplementation>, IMultipleMultitonRegistration<TInterface1, TInterface2, TImplementation> where TImplementation : TInterface1, TInterface2 /// <param name="scope">The <see cref="Type"/> of the multiton scope</param>
/// <param name="container">The current instance of the <see cref="IIocContainer"/></param>
public MultipleMultitonRegistration(Type interfaceType1, Type interfaceType2, Type implementationType, Type scope, IocContainer container)
: base(interfaceType1, implementationType, scope, container)
{ {
/// <summary> Registrations = new List<IRegistration>
/// An <see cref="IRegistrationBase"/> to register multiple interfaces for on implementation type that implements them as a multiton
/// </summary>
/// <param name="interfaceType1">The <see cref="Type"/> of the first interface</param>
/// <param name="interfaceType2">The <see cref="Type"/> of the second interface</param>
/// <param name="implementationType">The <see cref="Type"/> of the implementation</param>
/// <param name="scope">The <see cref="Type"/> of the multiton scope</param>
/// <param name="container">The current instance of the <see cref="IIocContainer"/></param>
public MultipleMultitonRegistration(Type interfaceType1, Type interfaceType2, Type implementationType, Type scope, IocContainer container)
: base(interfaceType1, implementationType, scope, container)
{ {
Registrations = new List<IRegistration> new MultitonRegistration<TInterface1, TImplementation>(interfaceType1, implementationType, scope, container),
{ new MultitonRegistration<TInterface2, TImplementation>(interfaceType2, implementationType, scope, container)
new MultitonRegistration<TInterface1, TImplementation>(interfaceType1, implementationType, scope, container), };
new MultitonRegistration<TInterface2, TImplementation>(interfaceType2, implementationType, scope, container) }
};
}
/// <summary> /// <summary>
/// A <see cref="List{T}"/> of <see cref="IRegistration"/>s that are registered within this <see cref="IMultipleRegistration{TInterface1,TImplementation}"/> /// A <see cref="List{T}"/> of <see cref="IRegistration"/>s that are registered within this <see cref="IMultipleRegistration{TInterface1,TImplementation}"/>
/// </summary> /// </summary>
public List<IRegistration> Registrations { get; } public List<IRegistration> Registrations { get; }
/// <summary> /// <summary>
/// Pass an <see cref="Action{T}"/> that will be invoked when an instance of this type is created /// Pass an <see cref="Action{T}"/> that will be invoked when an instance of this type is created
/// </summary> /// </summary>
/// <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="ITypedRegistration{TInterface,TImplementation}"/></returns> /// <returns>The current instance of this <see cref="ITypedRegistration{TInterface,TImplementation}"/></returns>
public override ITypedRegistration<TInterface1, TImplementation> OnCreate(Action<TImplementation?> action) public override ITypedRegistration<TInterface1, TImplementation> OnCreate(Action<TImplementation?> action)
{
foreach (IRegistration registration in Registrations)
{ {
foreach (IRegistration registration in Registrations) if (registration is IMultitonRegistration<TInterface2, TImplementation> interface2Registration)
{ interface2Registration.OnCreate(action);
if (registration is IMultitonRegistration<TInterface2, TImplementation> interface2Registration) else if (registration is IMultitonRegistration<TInterface1, TImplementation> interface1Registration)
interface2Registration.OnCreate(action); interface1Registration.OnCreate(action);
else if (registration is IMultitonRegistration<TInterface1, TImplementation> interface1Registration)
interface1Registration.OnCreate(action);
}
return this;
} }
return this;
} }
} }

@ -7,239 +7,238 @@ using System.Collections.Generic;
using LightweightIocContainer.Interfaces; using LightweightIocContainer.Interfaces;
using LightweightIocContainer.Interfaces.Registrations; using LightweightIocContainer.Interfaces.Registrations;
namespace LightweightIocContainer.Registrations namespace LightweightIocContainer.Registrations;
/// <summary>
/// The base class for every <see cref="IMultipleRegistration{TInterface1,TInterface2, TImplementation}"/> to register multiple interfaces
/// </summary>
/// <typeparam name="TInterface1">The first interface</typeparam>
/// <typeparam name="TImplementation">The implementation</typeparam>
internal abstract class MultipleRegistration<TInterface1, TImplementation> : TypedRegistration<TInterface1, TImplementation>, IMultipleRegistration<TInterface1, TImplementation> where TImplementation : TInterface1
{ {
/// <summary> /// <summary>
/// The base class for every <see cref="IMultipleRegistration{TInterface1,TInterface2, TImplementation}"/> to register multiple interfaces /// The base class for every <see cref="IMultipleRegistration{TInterface1,TInterface2}"/> to register multiple interfaces
/// </summary>
/// <param name="interfaceType1">The <see cref="Type"/> of the first interface</param>
/// <param name="implementationType">The <see cref="Type"/> of the implementation</param>
/// <param name="lifestyle">The <see cref="Lifestyle"/> of this <see cref="MultipleRegistration{TInterface1,TInterface2}"/></param>
/// <param name="container">The current instance of the <see cref="IIocContainer"/></param>
protected MultipleRegistration(Type interfaceType1, Type implementationType, Lifestyle lifestyle, IocContainer container)
: base(interfaceType1, implementationType, lifestyle, container) =>
Registrations = new List<IRegistration>();
/// <summary>
/// A <see cref="List{T}"/> of <see cref="IRegistration"/>s that are registered within this <see cref="MultipleRegistration{TInterface1,TInterface2}"/>
/// </summary>
public List<IRegistration> Registrations { get; protected init; }
}
/// <summary>
/// An <see cref="IRegistration"/> to register multiple interfaces for on implementation type
/// </summary>
/// <typeparam name="TInterface1">The first interface</typeparam>
/// <typeparam name="TInterface2">The second interface</typeparam>
/// <typeparam name="TImplementation">The implementation</typeparam>
internal class MultipleRegistration<TInterface1, TInterface2, TImplementation> : MultipleRegistration<TInterface1, TImplementation>, IMultipleRegistration<TInterface1, TInterface2, TImplementation> where TImplementation : TInterface1, TInterface2
{
/// <summary>
/// An <see cref="IRegistration"/> to register multiple interfaces for on implementation type
/// </summary> /// </summary>
/// <typeparam name="TInterface1">The first interface</typeparam> /// <param name="interfaceType1">The <see cref="Type"/> of the first interface</param>
/// <typeparam name="TImplementation">The implementation</typeparam> /// <param name="interfaceType2">The <see cref="Type"/> of the second interface</param>
internal abstract class MultipleRegistration<TInterface1, TImplementation> : TypedRegistration<TInterface1, TImplementation>, IMultipleRegistration<TInterface1, TImplementation> where TImplementation : TInterface1 /// <param name="implementationType">The <see cref="Type"/> of the implementation</param>
/// <param name="lifestyle">The <see cref="Lifestyle"/> of this <see cref="MultipleRegistration{TInterface1,TInterface2}"/></param>
/// <param name="container">The current instance of the <see cref="IIocContainer"/></param>
public MultipleRegistration(Type interfaceType1, Type interfaceType2, Type implementationType, Lifestyle lifestyle, IocContainer container)
: base(interfaceType1, implementationType, lifestyle, container)
{ {
/// <summary> Registrations = new List<IRegistration>
/// The base class for every <see cref="IMultipleRegistration{TInterface1,TInterface2}"/> to register multiple interfaces {
/// </summary> new TypedRegistration<TInterface1, TImplementation>(interfaceType1, implementationType, lifestyle, container),
/// <param name="interfaceType1">The <see cref="Type"/> of the first interface</param> new TypedRegistration<TInterface2, TImplementation>(interfaceType2, implementationType, lifestyle, container)
/// <param name="implementationType">The <see cref="Type"/> of the implementation</param> };
/// <param name="lifestyle">The <see cref="Lifestyle"/> of this <see cref="MultipleRegistration{TInterface1,TInterface2}"/></param>
/// <param name="container">The current instance of the <see cref="IIocContainer"/></param>
protected MultipleRegistration(Type interfaceType1, Type implementationType, Lifestyle lifestyle, IocContainer container)
: base(interfaceType1, implementationType, lifestyle, container) =>
Registrations = new List<IRegistration>();
/// <summary>
/// A <see cref="List{T}"/> of <see cref="IRegistration"/>s that are registered within this <see cref="MultipleRegistration{TInterface1,TInterface2}"/>
/// </summary>
public List<IRegistration> Registrations { get; protected init; }
} }
/// <summary> /// <summary>
/// An <see cref="IRegistration"/> to register multiple interfaces for on implementation type /// Pass an <see cref="Action{T}"/> that will be invoked when an instance of this type is created
/// </summary> /// </summary>
/// <typeparam name="TInterface1">The first interface</typeparam> /// <param name="action">The <see cref="Action{T}"/></param>
/// <typeparam name="TInterface2">The second interface</typeparam> /// <returns>The current instance of this <see cref="ITypedRegistration{TInterface,TImplementation}"/></returns>
/// <typeparam name="TImplementation">The implementation</typeparam> public override ITypedRegistration<TInterface1, TImplementation> OnCreate(Action<TImplementation?> action)
internal class MultipleRegistration<TInterface1, TInterface2, TImplementation> : MultipleRegistration<TInterface1, TImplementation>, IMultipleRegistration<TInterface1, TInterface2, TImplementation> where TImplementation : TInterface1, TInterface2
{ {
/// <summary> foreach (IRegistration registration in Registrations)
/// An <see cref="IRegistration"/> to register multiple interfaces for on implementation type
/// </summary>
/// <param name="interfaceType1">The <see cref="Type"/> of the first interface</param>
/// <param name="interfaceType2">The <see cref="Type"/> of the second interface</param>
/// <param name="implementationType">The <see cref="Type"/> of the implementation</param>
/// <param name="lifestyle">The <see cref="Lifestyle"/> of this <see cref="MultipleRegistration{TInterface1,TInterface2}"/></param>
/// <param name="container">The current instance of the <see cref="IIocContainer"/></param>
public MultipleRegistration(Type interfaceType1, Type interfaceType2, Type implementationType, Lifestyle lifestyle, IocContainer container)
: base(interfaceType1, implementationType, lifestyle, container)
{ {
Registrations = new List<IRegistration> if (registration is ITypedRegistration<TInterface2, TImplementation> interface2Registration)
{ interface2Registration.OnCreate(action);
new TypedRegistration<TInterface1, TImplementation>(interfaceType1, implementationType, lifestyle, container), else if (registration is ITypedRegistration<TInterface1, TImplementation> interface1Registration)
new TypedRegistration<TInterface2, TImplementation>(interfaceType2, implementationType, lifestyle, container) interface1Registration.OnCreate(action);
};
} }
/// <summary> return this;
/// Pass an <see cref="Action{T}"/> that will be invoked when an instance of this type is created
/// </summary>
/// <param name="action">The <see cref="Action{T}"/></param>
/// <returns>The current instance of this <see cref="ITypedRegistration{TInterface,TImplementation}"/></returns>
public override ITypedRegistration<TInterface1, TImplementation> OnCreate(Action<TImplementation?> action)
{
foreach (IRegistration registration in Registrations)
{
if (registration is ITypedRegistration<TInterface2, TImplementation> interface2Registration)
interface2Registration.OnCreate(action);
else if (registration is ITypedRegistration<TInterface1, TImplementation> interface1Registration)
interface1Registration.OnCreate(action);
}
return this;
}
} }
}
/// <summary>
/// An <see cref="IRegistration"/> to register multiple interfaces for on implementation type
/// </summary>
/// <typeparam name="TInterface1">The first interface</typeparam>
/// <typeparam name="TInterface2">The second interface</typeparam>
/// <typeparam name="TInterface3">The third interface</typeparam>
/// <typeparam name="TImplementation">The implementation</typeparam>
internal class MultipleRegistration<TInterface1, TInterface2, TInterface3, TImplementation> : MultipleRegistration<TInterface1, TImplementation>, IMultipleRegistration<TInterface1, TInterface2, TInterface3, TImplementation> where TImplementation : TInterface3, TInterface2, TInterface1
{
/// <summary> /// <summary>
/// An <see cref="IRegistration"/> to register multiple interfaces for on implementation type /// An <see cref="IRegistration"/> to register multiple interfaces for on implementation type
/// </summary> /// </summary>
/// <typeparam name="TInterface1">The first interface</typeparam> /// <param name="interfaceType1">The <see cref="Type"/> of the first interface</param>
/// <typeparam name="TInterface2">The second interface</typeparam> /// <param name="interfaceType2">The <see cref="Type"/> of the second interface</param>
/// <typeparam name="TInterface3">The third interface</typeparam> /// <param name="interfaceType3">The <see cref="Type"/> of the third interface</param>
/// <typeparam name="TImplementation">The implementation</typeparam> /// <param name="implementationType">The <see cref="Type"/> of the implementation</param>
internal class MultipleRegistration<TInterface1, TInterface2, TInterface3, TImplementation> : MultipleRegistration<TInterface1, TImplementation>, IMultipleRegistration<TInterface1, TInterface2, TInterface3, TImplementation> where TImplementation : TInterface3, TInterface2, TInterface1 /// <param name="lifestyle">The <see cref="Lifestyle"/> of this <see cref="MultipleRegistration{TInterface1,TInterface2}"/></param>
/// <param name="container">The current instance of the <see cref="IIocContainer"/></param>
public MultipleRegistration(Type interfaceType1, Type interfaceType2, Type interfaceType3, Type implementationType, Lifestyle lifestyle, IocContainer container)
: base(interfaceType1, implementationType, lifestyle, container)
{ {
/// <summary> Registrations = new List<IRegistration>
/// An <see cref="IRegistration"/> to register multiple interfaces for on implementation type
/// </summary>
/// <param name="interfaceType1">The <see cref="Type"/> of the first interface</param>
/// <param name="interfaceType2">The <see cref="Type"/> of the second interface</param>
/// <param name="interfaceType3">The <see cref="Type"/> of the third interface</param>
/// <param name="implementationType">The <see cref="Type"/> of the implementation</param>
/// <param name="lifestyle">The <see cref="Lifestyle"/> of this <see cref="MultipleRegistration{TInterface1,TInterface2}"/></param>
/// <param name="container">The current instance of the <see cref="IIocContainer"/></param>
public MultipleRegistration(Type interfaceType1, Type interfaceType2, Type interfaceType3, Type implementationType, Lifestyle lifestyle, IocContainer container)
: base(interfaceType1, implementationType, lifestyle, container)
{ {
Registrations = new List<IRegistration> new TypedRegistration<TInterface1, TImplementation>(interfaceType1, implementationType, lifestyle, container),
{ new TypedRegistration<TInterface2, TImplementation>(interfaceType2, implementationType, lifestyle, container),
new TypedRegistration<TInterface1, TImplementation>(interfaceType1, implementationType, lifestyle, container), new TypedRegistration<TInterface3, TImplementation>(interfaceType3, implementationType, lifestyle, container)
new TypedRegistration<TInterface2, TImplementation>(interfaceType2, implementationType, lifestyle, container), };
new TypedRegistration<TInterface3, TImplementation>(interfaceType3, implementationType, lifestyle, container) }
};
}
/// <summary> /// <summary>
/// Pass an <see cref="Action{T}"/> that will be invoked when an instance of this type is created /// Pass an <see cref="Action{T}"/> that will be invoked when an instance of this type is created
/// </summary> /// </summary>
/// <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="ITypedRegistration{TInterface,TImplementation}"/></returns> /// <returns>The current instance of this <see cref="ITypedRegistration{TInterface,TImplementation}"/></returns>
public override ITypedRegistration<TInterface1, TImplementation> OnCreate(Action<TImplementation?> action) public override ITypedRegistration<TInterface1, TImplementation> OnCreate(Action<TImplementation?> action)
{
foreach (IRegistration registration in Registrations)
{ {
foreach (IRegistration registration in Registrations) if (registration is ITypedRegistration<TInterface3, TImplementation> interface3Registration)
{ interface3Registration.OnCreate(action);
if (registration is ITypedRegistration<TInterface3, TImplementation> interface3Registration) else if (registration is ITypedRegistration<TInterface2, TImplementation> interface2Registration)
interface3Registration.OnCreate(action); interface2Registration.OnCreate(action);
else if (registration is ITypedRegistration<TInterface2, TImplementation> interface2Registration) else if (registration is ITypedRegistration<TInterface1, TImplementation> interface1Registration)
interface2Registration.OnCreate(action); interface1Registration.OnCreate(action);
else if (registration is ITypedRegistration<TInterface1, TImplementation> interface1Registration)
interface1Registration.OnCreate(action);
}
return this;
} }
return this;
} }
}
/// <summary>
/// An <see cref="IRegistration"/> to register multiple interfaces for on implementation type
/// </summary>
/// <typeparam name="TInterface1">The first interface</typeparam>
/// <typeparam name="TInterface2">The second interface</typeparam>
/// <typeparam name="TInterface3">The third interface</typeparam>
/// <typeparam name="TInterface4">The fourth interface</typeparam>
/// <typeparam name="TImplementation">The implementation</typeparam>
internal class MultipleRegistration<TInterface1, TInterface2, TInterface3, TInterface4, TImplementation> : MultipleRegistration<TInterface1, TImplementation>, IMultipleRegistration<TInterface1, TInterface2, TInterface3, TInterface4, TImplementation> where TImplementation : TInterface4, TInterface3, TInterface2, TInterface1
{
/// <summary> /// <summary>
/// An <see cref="IRegistration"/> to register multiple interfaces for on implementation type /// An <see cref="IRegistration"/> to register multiple interfaces for on implementation type
/// </summary> /// </summary>
/// <typeparam name="TInterface1">The first interface</typeparam> /// <param name="interfaceType1">The <see cref="Type"/> of the first interface</param>
/// <typeparam name="TInterface2">The second interface</typeparam> /// <param name="interfaceType2">The <see cref="Type"/> of the second interface</param>
/// <typeparam name="TInterface3">The third interface</typeparam> /// <param name="interfaceType3">The <see cref="Type"/> of the third interface</param>
/// <typeparam name="TInterface4">The fourth interface</typeparam> /// <param name="interfaceType4">The <see cref="Type"/> of the fourth interface</param>
/// <typeparam name="TImplementation">The implementation</typeparam> /// <param name="implementationType">The <see cref="Type"/> of the implementation</param>
internal class MultipleRegistration<TInterface1, TInterface2, TInterface3, TInterface4, TImplementation> : MultipleRegistration<TInterface1, TImplementation>, IMultipleRegistration<TInterface1, TInterface2, TInterface3, TInterface4, TImplementation> where TImplementation : TInterface4, TInterface3, TInterface2, TInterface1 /// <param name="lifestyle">The <see cref="Lifestyle"/> of this <see cref="MultipleRegistration{TInterface1,TInterface2}"/></param>
/// <param name="container">The current instance of the <see cref="IIocContainer"/></param>
public MultipleRegistration(Type interfaceType1, Type interfaceType2, Type interfaceType3, Type interfaceType4, Type implementationType, Lifestyle lifestyle, IocContainer container)
: base(interfaceType1, implementationType, lifestyle, container)
{ {
/// <summary> Registrations = new List<IRegistration>
/// An <see cref="IRegistration"/> to register multiple interfaces for on implementation type
/// </summary>
/// <param name="interfaceType1">The <see cref="Type"/> of the first interface</param>
/// <param name="interfaceType2">The <see cref="Type"/> of the second interface</param>
/// <param name="interfaceType3">The <see cref="Type"/> of the third interface</param>
/// <param name="interfaceType4">The <see cref="Type"/> of the fourth interface</param>
/// <param name="implementationType">The <see cref="Type"/> of the implementation</param>
/// <param name="lifestyle">The <see cref="Lifestyle"/> of this <see cref="MultipleRegistration{TInterface1,TInterface2}"/></param>
/// <param name="container">The current instance of the <see cref="IIocContainer"/></param>
public MultipleRegistration(Type interfaceType1, Type interfaceType2, Type interfaceType3, Type interfaceType4, Type implementationType, Lifestyle lifestyle, IocContainer container)
: base(interfaceType1, implementationType, lifestyle, container)
{ {
Registrations = new List<IRegistration> new TypedRegistration<TInterface1, TImplementation>(interfaceType1, implementationType, lifestyle, container),
{ new TypedRegistration<TInterface2, TImplementation>(interfaceType2, implementationType, lifestyle, container),
new TypedRegistration<TInterface1, TImplementation>(interfaceType1, implementationType, lifestyle, container), new TypedRegistration<TInterface3, TImplementation>(interfaceType3, implementationType, lifestyle, container),
new TypedRegistration<TInterface2, TImplementation>(interfaceType2, implementationType, lifestyle, container), new TypedRegistration<TInterface4, TImplementation>(interfaceType4, implementationType, lifestyle, container)
new TypedRegistration<TInterface3, TImplementation>(interfaceType3, implementationType, lifestyle, container), };
new TypedRegistration<TInterface4, TImplementation>(interfaceType4, implementationType, lifestyle, container) }
};
}
/// <summary> /// <summary>
/// Pass an <see cref="Action{T}"/> that will be invoked when an instance of this type is created /// Pass an <see cref="Action{T}"/> that will be invoked when an instance of this type is created
/// </summary> /// </summary>
/// <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="ITypedRegistration{TInterface,TImplementation}"/></returns> /// <returns>The current instance of this <see cref="ITypedRegistration{TInterface,TImplementation}"/></returns>
public override ITypedRegistration<TInterface1, TImplementation> OnCreate(Action<TImplementation?> action) public override ITypedRegistration<TInterface1, TImplementation> OnCreate(Action<TImplementation?> action)
{
foreach (IRegistration registration in Registrations)
{ {
foreach (IRegistration registration in Registrations) if (registration is ITypedRegistration<TInterface4, TImplementation> interface4Registration)
{ interface4Registration.OnCreate(action);
if (registration is ITypedRegistration<TInterface4, TImplementation> interface4Registration) else if (registration is ITypedRegistration<TInterface3, TImplementation> interface3Registration)
interface4Registration.OnCreate(action); interface3Registration.OnCreate(action);
else if (registration is ITypedRegistration<TInterface3, TImplementation> interface3Registration) else if (registration is ITypedRegistration<TInterface2, TImplementation> interface2Registration)
interface3Registration.OnCreate(action); interface2Registration.OnCreate(action);
else if (registration is ITypedRegistration<TInterface2, TImplementation> interface2Registration) else if (registration is ITypedRegistration<TInterface1, TImplementation> interface1Registration)
interface2Registration.OnCreate(action); interface1Registration.OnCreate(action);
else if (registration is ITypedRegistration<TInterface1, TImplementation> interface1Registration)
interface1Registration.OnCreate(action);
}
return this;
} }
return this;
} }
}
/// <summary>
/// An <see cref="IRegistration"/> to register multiple interfaces for on implementation type
/// </summary>
/// <typeparam name="TInterface1">The first interface</typeparam>
/// <typeparam name="TInterface2">The second interface</typeparam>
/// <typeparam name="TInterface3">The third interface</typeparam>
/// <typeparam name="TInterface4">The fourth interface</typeparam>
/// <typeparam name="TInterface5">The fifth interface</typeparam>
/// <typeparam name="TImplementation">The implementation</typeparam>
internal class MultipleRegistration<TInterface1, TInterface2, TInterface3, TInterface4, TInterface5, TImplementation> : MultipleRegistration<TInterface1, TImplementation>, IMultipleRegistration<TInterface1, TInterface2, TInterface3, TInterface4, TInterface5, TImplementation> where TImplementation : TInterface5, TInterface4, TInterface3, TInterface2, TInterface1
{
/// <summary> /// <summary>
/// An <see cref="IRegistration"/> to register multiple interfaces for on implementation type /// An <see cref="IRegistration"/> to register multiple interfaces for on implementation type
/// </summary> /// </summary>
/// <typeparam name="TInterface1">The first interface</typeparam> /// <param name="interfaceType1">The <see cref="Type"/> of the first interface</param>
/// <typeparam name="TInterface2">The second interface</typeparam> /// <param name="interfaceType2">The <see cref="Type"/> of the second interface</param>
/// <typeparam name="TInterface3">The third interface</typeparam> /// <param name="interfaceType3">The <see cref="Type"/> of the third interface</param>
/// <typeparam name="TInterface4">The fourth interface</typeparam> /// <param name="interfaceType4">The <see cref="Type"/> of the fourth interface</param>
/// <typeparam name="TInterface5">The fifth interface</typeparam> /// <param name="interfaceType5">The <see cref="Type"/> of the fifth interface</param>
/// <typeparam name="TImplementation">The implementation</typeparam> /// <param name="implementationType">The <see cref="Type"/> of the implementation</param>
internal class MultipleRegistration<TInterface1, TInterface2, TInterface3, TInterface4, TInterface5, TImplementation> : MultipleRegistration<TInterface1, TImplementation>, IMultipleRegistration<TInterface1, TInterface2, TInterface3, TInterface4, TInterface5, TImplementation> where TImplementation : TInterface5, TInterface4, TInterface3, TInterface2, TInterface1 /// <param name="lifestyle">The <see cref="Lifestyle"/> of this <see cref="MultipleRegistration{TInterface1,TInterface2}"/></param>
/// <param name="container">The current instance of the <see cref="IIocContainer"/></param>
public MultipleRegistration(Type interfaceType1, Type interfaceType2, Type interfaceType3, Type interfaceType4, Type interfaceType5, Type implementationType, Lifestyle lifestyle, IocContainer container)
: base(interfaceType1, implementationType, lifestyle, container)
{ {
/// <summary> Registrations = new List<IRegistration>
/// An <see cref="IRegistration"/> to register multiple interfaces for on implementation type
/// </summary>
/// <param name="interfaceType1">The <see cref="Type"/> of the first interface</param>
/// <param name="interfaceType2">The <see cref="Type"/> of the second interface</param>
/// <param name="interfaceType3">The <see cref="Type"/> of the third interface</param>
/// <param name="interfaceType4">The <see cref="Type"/> of the fourth interface</param>
/// <param name="interfaceType5">The <see cref="Type"/> of the fifth interface</param>
/// <param name="implementationType">The <see cref="Type"/> of the implementation</param>
/// <param name="lifestyle">The <see cref="Lifestyle"/> of this <see cref="MultipleRegistration{TInterface1,TInterface2}"/></param>
/// <param name="container">The current instance of the <see cref="IIocContainer"/></param>
public MultipleRegistration(Type interfaceType1, Type interfaceType2, Type interfaceType3, Type interfaceType4, Type interfaceType5, Type implementationType, Lifestyle lifestyle, IocContainer container)
: base(interfaceType1, implementationType, lifestyle, container)
{ {
Registrations = new List<IRegistration> new TypedRegistration<TInterface1, TImplementation>(interfaceType1, implementationType, lifestyle, container),
{ new TypedRegistration<TInterface2, TImplementation>(interfaceType2, implementationType, lifestyle, container),
new TypedRegistration<TInterface1, TImplementation>(interfaceType1, implementationType, lifestyle, container), new TypedRegistration<TInterface3, TImplementation>(interfaceType3, implementationType, lifestyle, container),
new TypedRegistration<TInterface2, TImplementation>(interfaceType2, implementationType, lifestyle, container), new TypedRegistration<TInterface4, TImplementation>(interfaceType4, implementationType, lifestyle, container),
new TypedRegistration<TInterface3, TImplementation>(interfaceType3, implementationType, lifestyle, container), new TypedRegistration<TInterface5, TImplementation>(interfaceType5, implementationType, lifestyle, container)
new TypedRegistration<TInterface4, TImplementation>(interfaceType4, implementationType, lifestyle, container), };
new TypedRegistration<TInterface5, TImplementation>(interfaceType5, implementationType, lifestyle, container) }
};
}
/// <summary> /// <summary>
/// Pass an <see cref="Action{T}"/> that will be invoked when an instance of this type is created /// Pass an <see cref="Action{T}"/> that will be invoked when an instance of this type is created
/// </summary> /// </summary>
/// <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="ITypedRegistration{TInterface,TImplementation}"/></returns> /// <returns>The current instance of this <see cref="ITypedRegistration{TInterface,TImplementation}"/></returns>
public override ITypedRegistration<TInterface1, TImplementation> OnCreate(Action<TImplementation?> action) public override ITypedRegistration<TInterface1, TImplementation> OnCreate(Action<TImplementation?> action)
{
foreach (IRegistration registration in Registrations)
{ {
foreach (IRegistration registration in Registrations) if (registration is ITypedRegistration<TInterface5, TImplementation> interface5Registration)
{ interface5Registration.OnCreate(action);
if (registration is ITypedRegistration<TInterface5, TImplementation> interface5Registration) else if (registration is ITypedRegistration<TInterface4, TImplementation> interface4Registration)
interface5Registration.OnCreate(action); interface4Registration.OnCreate(action);
else if (registration is ITypedRegistration<TInterface4, TImplementation> interface4Registration) else if (registration is ITypedRegistration<TInterface3, TImplementation> interface3Registration)
interface4Registration.OnCreate(action); interface3Registration.OnCreate(action);
else if (registration is ITypedRegistration<TInterface3, TImplementation> interface3Registration) else if (registration is ITypedRegistration<TInterface2, TImplementation> interface2Registration)
interface3Registration.OnCreate(action); interface2Registration.OnCreate(action);
else if (registration is ITypedRegistration<TInterface2, TImplementation> interface2Registration) else if (registration is ITypedRegistration<TInterface1, TImplementation> interface1Registration)
interface2Registration.OnCreate(action); interface1Registration.OnCreate(action);
else if (registration is ITypedRegistration<TInterface1, TImplementation> interface1Registration)
interface1Registration.OnCreate(action);
}
return this;
} }
return this;
} }
} }

@ -8,52 +8,51 @@ using LightweightIocContainer.Exceptions;
using LightweightIocContainer.Interfaces; using LightweightIocContainer.Interfaces;
using LightweightIocContainer.Interfaces.Registrations; using LightweightIocContainer.Interfaces.Registrations;
namespace LightweightIocContainer.Registrations namespace LightweightIocContainer.Registrations;
/// <summary>
/// The registration that is used to register a multiton
/// </summary>
/// <typeparam name="TInterface">The registered interface</typeparam>
/// <typeparam name="TImplementation">The registered implementation</typeparam>
internal class MultitonRegistration<TInterface, TImplementation> : TypedRegistration<TInterface, TImplementation>, IMultitonRegistration<TInterface, TImplementation> where TImplementation : TInterface
{ {
/// <summary> /// <summary>
/// The registration that is used to register a multiton /// The registration that is used to register a multiton
/// </summary> /// </summary>
/// <typeparam name="TInterface">The registered interface</typeparam> /// <param name="interfaceType">The <see cref="Type"/> of the Interface</param>
/// <typeparam name="TImplementation">The registered implementation</typeparam> /// <param name="implementationType">The <see cref="Type"/> of the Implementation</param>
internal class MultitonRegistration<TInterface, TImplementation> : TypedRegistration<TInterface, TImplementation>, IMultitonRegistration<TInterface, TImplementation> where TImplementation : TInterface /// <param name="scope">The <see cref="Type"/> of the Multiton Scope</param>
{ /// <param name="container">The current instance of the <see cref="IIocContainer"/></param>
/// <summary> public MultitonRegistration(Type interfaceType, Type implementationType, Type scope, IocContainer container)
/// The registration that is used to register a multiton : base(interfaceType, implementationType, Lifestyle.Multiton, container) =>
/// </summary> Scope = scope;
/// <param name="interfaceType">The <see cref="Type"/> of the Interface</param>
/// <param name="implementationType">The <see cref="Type"/> of the Implementation</param>
/// <param name="scope">The <see cref="Type"/> of the Multiton Scope</param>
/// <param name="container">The current instance of the <see cref="IIocContainer"/></param>
public MultitonRegistration(Type interfaceType, Type implementationType, Type scope, IocContainer container)
: base(interfaceType, implementationType, Lifestyle.Multiton, container) =>
Scope = scope;
/// <summary> /// <summary>
/// The <see cref="Type"/> of the multiton scope /// The <see cref="Type"/> of the multiton scope
/// </summary> /// </summary>
public Type Scope { get; } public Type Scope { get; }
/// <summary> /// <summary>
/// Validate the <see cref="RegistrationBase.Factory"/> /// Validate the <see cref="RegistrationBase.Factory"/>
/// </summary> /// </summary>
protected override void ValidateFactory() protected override void ValidateFactory()
{ {
if (Factory == null) if (Factory == null)
return; return;
if (Factory.CreateMethods.Any(c => c.GetParameters().Length == 0)) if (Factory.CreateMethods.Any(c => c.GetParameters().Length == 0))
throw new InvalidFactoryRegistrationException($"Create methods without parameters are not valid for multitons (Type: {InterfaceType})."); throw new InvalidFactoryRegistrationException($"Create methods without parameters are not valid for multitons (Type: {InterfaceType}).");
if (Factory.CreateMethods.Any(c => c.GetParameters()[0].ParameterType != Scope)) if (Factory.CreateMethods.Any(c => c.GetParameters()[0].ParameterType != Scope))
throw new InvalidFactoryRegistrationException($"Create methods without scope type ({Scope}) as first parameter are not valid for multitons (Type: {InterfaceType})."); throw new InvalidFactoryRegistrationException($"Create methods without scope type ({Scope}) as first parameter are not valid for multitons (Type: {InterfaceType}).");
base.ValidateFactory(); base.ValidateFactory();
} }
public override bool Equals(object? obj) => obj is MultitonRegistration<TInterface, TImplementation> multitonRegistration && public override bool Equals(object? obj) => obj is MultitonRegistration<TInterface, TImplementation> multitonRegistration &&
base.Equals(obj) && base.Equals(obj) &&
Scope == multitonRegistration.Scope; Scope == multitonRegistration.Scope;
public override int GetHashCode() => HashCode.Combine(base.GetHashCode(), Scope); public override int GetHashCode() => HashCode.Combine(base.GetHashCode(), Scope);
}
} }

@ -7,47 +7,46 @@ using LightweightIocContainer.Exceptions;
using LightweightIocContainer.Interfaces; using LightweightIocContainer.Interfaces;
using LightweightIocContainer.Interfaces.Registrations; using LightweightIocContainer.Interfaces.Registrations;
namespace LightweightIocContainer.Registrations namespace LightweightIocContainer.Registrations;
/// <summary>
/// <see cref="IRegistration"/> for open generic types
/// </summary>
internal class OpenGenericRegistration : RegistrationBase, IOpenGenericRegistration
{ {
/// <summary> /// <summary>
/// <see cref="IRegistration"/> for open generic types /// <see cref="IRegistration"/> for open generic types
/// </summary> /// </summary>
internal class OpenGenericRegistration : RegistrationBase, IOpenGenericRegistration /// <param name="interfaceType">The <see cref="Type"/> of the interface</param>
{ /// <param name="implementationType">The <see cref="Type"/> of the implementation type</param>
/// <summary> /// <param name="lifestyle">The <see cref="Lifestyle"/> of this <see cref="IOpenGenericRegistration"/></param>
/// <see cref="IRegistration"/> for open generic types /// <param name="iocContainer">The current instance of the <see cref="IIocContainer"/></param>
/// </summary> public OpenGenericRegistration(Type interfaceType, Type implementationType, Lifestyle lifestyle, IocContainer iocContainer)
/// <param name="interfaceType">The <see cref="Type"/> of the interface</param> : base(interfaceType, lifestyle, iocContainer) =>
/// <param name="implementationType">The <see cref="Type"/> of the implementation type</param> ImplementationType = implementationType;
/// <param name="lifestyle">The <see cref="Lifestyle"/> of this <see cref="IOpenGenericRegistration"/></param>
/// <param name="iocContainer">The current instance of the <see cref="IIocContainer"/></param>
public OpenGenericRegistration(Type interfaceType, Type implementationType, Lifestyle lifestyle, IocContainer iocContainer)
: base(interfaceType, lifestyle, iocContainer) =>
ImplementationType = implementationType;
/// <summary> /// <summary>
/// The <see cref="Type"/> that implements the <see cref="IRegistration.InterfaceType"/> that is registered with this <see cref="IOpenGenericRegistration"/> /// The <see cref="Type"/> that implements the <see cref="IRegistration.InterfaceType"/> that is registered with this <see cref="IOpenGenericRegistration"/>
/// </summary> /// </summary>
public Type ImplementationType { get; } public Type ImplementationType { get; }
/// <summary> /// <summary>
/// Validate this <see cref="OpenGenericRegistration"/> /// Validate this <see cref="OpenGenericRegistration"/>
/// </summary> /// </summary>
public override void Validate() public override void Validate()
{ {
if (!InterfaceType.ContainsGenericParameters) if (!InterfaceType.ContainsGenericParameters)
throw new InvalidRegistrationException("This function can only be used to register open generic types."); throw new InvalidRegistrationException("This function can only be used to register open generic types.");
if (Lifestyle == Lifestyle.Multiton) if (Lifestyle == Lifestyle.Multiton)
throw new InvalidRegistrationException("Can't register a multiton with open generic registration."); //TODO: Is there any need to register multitons with open generics? throw new InvalidRegistrationException("Can't register a multiton with open generic registration."); //TODO: Is there any need to register multitons with open generics?
base.Validate(); base.Validate();
} }
public override bool Equals(object? obj) => obj is OpenGenericRegistration openGenericRegistration && public override bool Equals(object? obj) => obj is OpenGenericRegistration openGenericRegistration &&
base.Equals(obj) && base.Equals(obj) &&
ImplementationType == openGenericRegistration.ImplementationType; ImplementationType == openGenericRegistration.ImplementationType;
public override int GetHashCode() => HashCode.Combine(base.GetHashCode(), ImplementationType); public override int GetHashCode() => HashCode.Combine(base.GetHashCode(), ImplementationType);
}
} }

@ -12,236 +12,235 @@ using LightweightIocContainer.Interfaces.Registrations;
using LightweightIocContainer.Interfaces.Registrations.Fluent; using LightweightIocContainer.Interfaces.Registrations.Fluent;
using LightweightIocContainer.ResolvePlaceholders; using LightweightIocContainer.ResolvePlaceholders;
namespace LightweightIocContainer.Registrations namespace LightweightIocContainer.Registrations;
/// <summary>
/// The <see cref="RegistrationBase"/> that is used to register an Interface
/// </summary>
internal abstract class RegistrationBase : IRegistrationBase, IWithFactoryInternal, IWithParametersInternal, ILifestyleProvider, IWithDisposeStrategyInternal, IInternalValidationProvider
{ {
private readonly IocContainer _container;
/// <summary> /// <summary>
/// The <see cref="RegistrationBase"/> that is used to register an Interface /// The <see cref="RegistrationBase"/> that is used to register an Interface
/// </summary> /// </summary>
internal abstract class RegistrationBase : IRegistrationBase, IWithFactoryInternal, IWithParametersInternal, ILifestyleProvider, IWithDisposeStrategyInternal, IInternalValidationProvider /// <param name="interfaceType">The <see cref="Type"/> of the Interface</param>
/// <param name="lifestyle">The <see cref="LightweightIocContainer.Lifestyle"/> of the registration</param>
/// <param name="container">The current instance of the <see cref="IocContainer"/></param>
protected RegistrationBase(Type interfaceType, Lifestyle lifestyle, IocContainer container)
{ {
private readonly IocContainer _container; InterfaceType = interfaceType;
Lifestyle = lifestyle;
/// <summary> _container = container;
/// The <see cref="RegistrationBase"/> that is used to register an Interface }
/// </summary>
/// <param name="interfaceType">The <see cref="Type"/> of the Interface</param>
/// <param name="lifestyle">The <see cref="LightweightIocContainer.Lifestyle"/> of the registration</param>
/// <param name="container">The current instance of the <see cref="IocContainer"/></param>
protected RegistrationBase(Type interfaceType, Lifestyle lifestyle, IocContainer container)
{
InterfaceType = interfaceType;
Lifestyle = lifestyle;
_container = container;
}
/// <summary> /// <summary>
/// The <see cref="Type"/> of the Interface that is registered with this <see cref="RegistrationBase"/> /// The <see cref="Type"/> of the Interface that is registered with this <see cref="RegistrationBase"/>
/// </summary> /// </summary>
public Type InterfaceType { get; } public Type InterfaceType { get; }
/// <summary> /// <summary>
/// The <see cref="LightweightIocContainer.Lifestyle"/> of Instances that are created with this <see cref="RegistrationBase"/> /// The <see cref="LightweightIocContainer.Lifestyle"/> of Instances that are created with this <see cref="RegistrationBase"/>
/// </summary> /// </summary>
public Lifestyle Lifestyle { get; } public Lifestyle Lifestyle { get; }
/// <summary> /// <summary>
/// The <see cref="LightweightIocContainer.DisposeStrategy"/> of singletons/multitons that implement <see cref="IDisposable"/> and are created with this <see cref="RegistrationBase"/> /// The <see cref="LightweightIocContainer.DisposeStrategy"/> of singletons/multitons that implement <see cref="IDisposable"/> and are created with this <see cref="RegistrationBase"/>
/// </summary> /// </summary>
public DisposeStrategy DisposeStrategy { get; private set; } public DisposeStrategy DisposeStrategy { get; private set; }
/// <summary> /// <summary>
/// An <see cref="Array"/> of parameters that are used to <see cref="IocContainer.Resolve{T}()"/> an instance of this <see cref="IRegistration.InterfaceType"/> /// An <see cref="Array"/> of parameters that are used to <see cref="IocContainer.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> /// <para>Can be set in the <see cref="IIocInstaller"/> by calling <see cref="WithParameters(object[])"/></para>
/// </summary> /// </summary>
public object[]? Parameters { get; private set; } public object[]? Parameters { get; private set; }
/// <summary> /// <summary>
/// The Factory added with the <see cref="WithFactory{TFactory}"/> method /// The Factory added with the <see cref="WithFactory{TFactory}"/> method
/// </summary> /// </summary>
public ITypedFactory? Factory { get; private set; } public ITypedFactory? Factory { get; private set; }
/// <summary>
/// Pass parameters that will be used to <see cref="IocContainer.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="IRegistration"/></returns>
/// <exception cref="InvalidRegistrationException"><see cref="Parameters"/> are already set or no parameters given</exception>
public virtual IRegistrationBase WithParameters(params object[] parameters)
{
if (Parameters != null)
throw new InvalidRegistrationException($"Don't use `WithParameters()` method twice (Type: {InterfaceType}).");
if (parameters == null || !parameters.Any()) /// <summary>
throw new InvalidRegistrationException($"No parameters given to `WithParameters()` method (Type: {InterfaceType})."); /// Pass parameters that will be used to <see cref="IocContainer.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="IRegistration"/></returns>
/// <exception cref="InvalidRegistrationException"><see cref="Parameters"/> are already set or no parameters given</exception>
public virtual IRegistrationBase WithParameters(params object[] parameters)
{
if (Parameters != null)
throw new InvalidRegistrationException($"Don't use `WithParameters()` method twice (Type: {InterfaceType}).");
Parameters = parameters; if (parameters == null || !parameters.Any())
return this; throw new InvalidRegistrationException($"No parameters given to `WithParameters()` method (Type: {InterfaceType}).");
}
/// <summary> Parameters = parameters;
/// Pass parameters that will be used to<see cref="IocContainer.Resolve{T}()"/> an instance of this <see cref="IRegistration.InterfaceType"/> return this;
/// <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="IRegistration"/></returns>
/// <exception cref="InvalidRegistrationException"><see cref="Parameters"/> are already set or no parameters given</exception>
public virtual 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()) /// <summary>
throw new InvalidRegistrationException($"No parameters given to `WithParameters()` method (Type: {InterfaceType})."); /// Pass parameters that will be used to<see cref="IocContainer.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="IRegistration"/></returns>
/// <exception cref="InvalidRegistrationException"><see cref="Parameters"/> are already set or no parameters given</exception>
public virtual IRegistrationBase WithParameters(params (int index, object parameter)[] parameters)
{
if (Parameters != null)
throw new InvalidRegistrationException($"Don't use `WithParameters()` method twice (Type: {InterfaceType}).");
int lastIndex = parameters.Max(p => p.index); if (parameters == null || !parameters.Any())
Parameters = new object[lastIndex + 1]; throw new InvalidRegistrationException($"No parameters given to `WithParameters()` method (Type: {InterfaceType}).");
for (int i = 0; i < Parameters.Length; i++) int lastIndex = parameters.Max(p => p.index);
{ Parameters = new object[lastIndex + 1];
if (parameters.Any(p => p.index == i))
Parameters[i] = parameters.First(p => p.index == i).parameter;
else
Parameters[i] = new InternalResolvePlaceholder();
}
return this; 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();
} }
/// <summary> return this;
/// Register an abstract typed factory for the <see cref="IRegistrationBase"/> }
/// </summary>
/// <typeparam name="TFactory">The type of the abstract typed factory</typeparam> /// <summary>
/// <returns>The current instance of this <see cref="IRegistrationBase"/></returns> /// Register an abstract typed factory for the <see cref="IRegistrationBase"/>
public IRegistrationBase WithFactory<TFactory>() /// </summary>
{ /// <typeparam name="TFactory">The type of the abstract typed factory</typeparam>
TypedFactory<TFactory> factory = new(_container); /// <returns>The current instance of this <see cref="IRegistrationBase"/></returns>
Factory = factory; public IRegistrationBase WithFactory<TFactory>()
{
TypedFactory<TFactory> factory = new(_container);
Factory = factory;
_container.RegisterFactory(factory); _container.RegisterFactory(factory);
return this; return this;
} }
/// <summary> /// <summary>
/// Register a custom implemented factory for the <see cref="IRegistrationBase"/> /// Register a custom implemented factory for the <see cref="IRegistrationBase"/>
/// </summary> /// </summary>
/// <typeparam name="TFactoryInterface">The type of the interface for the custom factory</typeparam> /// <typeparam name="TFactoryInterface">The type of the interface for the custom factory</typeparam>
/// <typeparam name="TFactoryImplementation">The type of the implementation for the custom factory</typeparam> /// <typeparam name="TFactoryImplementation">The type of the implementation for the custom factory</typeparam>
/// <returns>The current instance of this <see cref="IRegistrationBase"/></returns> /// <returns>The current instance of this <see cref="IRegistrationBase"/></returns>
public IRegistrationBase WithFactory<TFactoryInterface, TFactoryImplementation>() where TFactoryImplementation : TFactoryInterface public IRegistrationBase WithFactory<TFactoryInterface, TFactoryImplementation>() where TFactoryImplementation : TFactoryInterface
{ {
Factory = new CustomTypedFactory<TFactoryInterface>(); Factory = new CustomTypedFactory<TFactoryInterface>();
_container.Register(r => r.Add<TFactoryInterface, TFactoryImplementation>()); _container.Register(r => r.Add<TFactoryInterface, TFactoryImplementation>());
return this; return this;
} }
/// <summary> /// <summary>
/// Add a <see cref="DisposeStrategy"/> for the <see cref="IRegistrationBase"/> /// Add a <see cref="DisposeStrategy"/> for the <see cref="IRegistrationBase"/>
/// </summary> /// </summary>
/// <param name="disposeStrategy">The <see cref="DisposeStrategy"/></param> /// <param name="disposeStrategy">The <see cref="DisposeStrategy"/></param>
/// <returns>The current instance of this <see cref="RegistrationBase"/></returns> /// <returns>The current instance of this <see cref="RegistrationBase"/></returns>
public IRegistrationBase WithDisposeStrategy(DisposeStrategy disposeStrategy) public IRegistrationBase WithDisposeStrategy(DisposeStrategy disposeStrategy)
{ {
DisposeStrategy = disposeStrategy; DisposeStrategy = disposeStrategy;
return this; return this;
} }
/// <summary> /// <summary>
/// Validate this <see cref="RegistrationBase"/> /// Validate this <see cref="RegistrationBase"/>
/// </summary> /// </summary>
public virtual void Validate() public virtual void Validate()
{ {
ValidateMultiton(); ValidateMultiton();
ValidateFactory(); ValidateFactory();
ValidateDisposeStrategy(); ValidateDisposeStrategy();
} }
/// <summary> /// <summary>
/// Validate that no registration that isn't derived from <see cref="IMultitonRegistration"/> has <see cref="LightweightIocContainer.Lifestyle.Multiton"/> /// Validate that no registration that isn't derived from <see cref="IMultitonRegistration"/> has <see cref="LightweightIocContainer.Lifestyle.Multiton"/>
/// </summary> /// </summary>
/// <exception cref="InvalidRegistrationException"></exception> /// <exception cref="InvalidRegistrationException"></exception>
private void ValidateMultiton() private void ValidateMultiton()
{ {
//don't allow lifestyle.multiton without iMultitonRegistration //don't allow lifestyle.multiton without iMultitonRegistration
if (Lifestyle == Lifestyle.Multiton && this is not IMultitonRegistration) if (Lifestyle == Lifestyle.Multiton && this is not IMultitonRegistration)
throw new InvalidRegistrationException("Can't register a type as Lifestyle.Multiton without a scope (Registration is not of type IMultitonRegistration)."); throw new InvalidRegistrationException("Can't register a type as Lifestyle.Multiton without a scope (Registration is not of type IMultitonRegistration).");
} }
/// <summary> /// <summary>
/// Validate the <see cref="Factory"/> /// Validate the <see cref="Factory"/>
/// </summary> /// </summary>
/// <exception cref="InvalidFactoryRegistrationException">No create method that can create the <see cref="InterfaceType"/></exception> /// <exception cref="InvalidFactoryRegistrationException">No create method that can create the <see cref="InterfaceType"/></exception>
protected virtual void ValidateFactory() protected virtual void ValidateFactory()
{ {
if (Factory == null) if (Factory == null)
return; return;
if (Factory.CreateMethods.All(c => c.ReturnType != InterfaceType)) if (Factory.CreateMethods.All(c => c.ReturnType != InterfaceType))
throw new InvalidFactoryRegistrationException($"No create method that can create {InterfaceType}."); throw new InvalidFactoryRegistrationException($"No create method that can create {InterfaceType}.");
} }
/// <summary> /// <summary>
/// Validate the <see cref="DisposeStrategy"/> for the <see cref="InterfaceType"/> and <see cref="Lifestyle"/> /// Validate the <see cref="DisposeStrategy"/> for the <see cref="InterfaceType"/> and <see cref="Lifestyle"/>
/// </summary> /// </summary>
protected virtual void ValidateDisposeStrategy() => ValidateDisposeStrategy(InterfaceType); protected virtual void ValidateDisposeStrategy() => ValidateDisposeStrategy(InterfaceType);
/// <summary> /// <summary>
/// Validate the <see cref="DisposeStrategy"/> for the given <see cref="Type"/> and <see cref="Lifestyle"/> /// Validate the <see cref="DisposeStrategy"/> for the given <see cref="Type"/> and <see cref="Lifestyle"/>
/// </summary> /// </summary>
/// <param name="type">The given <see cref="Type"/></param> /// <param name="type">The given <see cref="Type"/></param>
/// <exception cref="InvalidDisposeStrategyException">Dispose strategy is invalid for this <see cref="InterfaceType"/> and <see cref="Lifestyle"/></exception> /// <exception cref="InvalidDisposeStrategyException">Dispose strategy is invalid for this <see cref="InterfaceType"/> and <see cref="Lifestyle"/></exception>
protected void ValidateDisposeStrategy(Type type) protected void ValidateDisposeStrategy(Type type)
{
if (Lifestyle == Lifestyle.Transient)
{ {
if (Lifestyle == Lifestyle.Transient) if (DisposeStrategy != DisposeStrategy.None)
throw new InvalidDisposeStrategyException(DisposeStrategy, type, Lifestyle);
}
else
{
if (type.IsAssignableTo(typeof(IDisposable)))
{ {
if (DisposeStrategy != DisposeStrategy.None) if (DisposeStrategy == DisposeStrategy.None)
throw new InvalidDisposeStrategyException(DisposeStrategy, type, Lifestyle); throw new InvalidDisposeStrategyException(DisposeStrategy, type, Lifestyle);
} }
else else
{ {
if (type.IsAssignableTo(typeof(IDisposable))) if (DisposeStrategy != DisposeStrategy.None)
{ throw new InvalidDisposeStrategyException(DisposeStrategy, type, Lifestyle);
if (DisposeStrategy == DisposeStrategy.None)
throw new InvalidDisposeStrategyException(DisposeStrategy, type, Lifestyle);
}
else
{
if (DisposeStrategy != DisposeStrategy.None)
throw new InvalidDisposeStrategyException(DisposeStrategy, type, Lifestyle);
}
} }
} }
}
public override bool Equals(object? obj) public override bool Equals(object? obj)
{ {
if (obj is not RegistrationBase registrationBase) if (obj is not RegistrationBase registrationBase)
return false; return false;
if (Parameters == null && registrationBase.Parameters != null) if (Parameters == null && registrationBase.Parameters != null)
return false; return false;
if (Parameters != null && registrationBase.Parameters == null) if (Parameters != null && registrationBase.Parameters == null)
return false; return false;
if (Parameters?.Length != registrationBase.Parameters?.Length) if (Parameters?.Length != registrationBase.Parameters?.Length)
return false; return false;
if (Factory == null && registrationBase.Factory != null) if (Factory == null && registrationBase.Factory != null)
return false; return false;
if (Factory != null && registrationBase.Factory == null) if (Factory != null && registrationBase.Factory == null)
return false; return false;
if (Factory?.CreateMethods.Count != registrationBase.Factory?.CreateMethods.Count) if (Factory?.CreateMethods.Count != registrationBase.Factory?.CreateMethods.Count)
return false; return false;
return InterfaceType == registrationBase.InterfaceType && return InterfaceType == registrationBase.InterfaceType &&
Lifestyle == registrationBase.Lifestyle && Lifestyle == registrationBase.Lifestyle &&
DisposeStrategy == registrationBase.DisposeStrategy; DisposeStrategy == registrationBase.DisposeStrategy;
}
public override int GetHashCode() => HashCode.Combine(InterfaceType, (int) Lifestyle);
} }
public override int GetHashCode() => HashCode.Combine(InterfaceType, (int) Lifestyle);
} }

@ -7,121 +7,120 @@ using LightweightIocContainer.Interfaces.Factories;
using LightweightIocContainer.Interfaces.Installers; using LightweightIocContainer.Interfaces.Installers;
using LightweightIocContainer.Interfaces.Registrations; using LightweightIocContainer.Interfaces.Registrations;
namespace LightweightIocContainer.Registrations namespace LightweightIocContainer.Registrations;
/// <summary>
/// A factory to register interfaces and factories in an <see cref="IIocInstaller"/> and create the needed <see cref="IRegistration"/>s
/// </summary>
internal class RegistrationFactory
{ {
/// <summary> private readonly IocContainer _iocContainer;
/// A factory to register interfaces and factories in an <see cref="IIocInstaller"/> and create the needed <see cref="IRegistration"/>s
/// </summary>
internal class RegistrationFactory
{
private readonly IocContainer _iocContainer;
internal RegistrationFactory(IocContainer container) => _iocContainer = container; internal RegistrationFactory(IocContainer container) => _iocContainer = container;
/// <summary> /// <summary>
/// Register an Interface with a Type that implements it and create a <see cref="ITypedRegistration{TInterface,TImplementation}"/> /// Register an Interface with a Type that implements it and create a <see cref="ITypedRegistration{TInterface,TImplementation}"/>
/// </summary> /// </summary>
/// <typeparam name="TInterface">The Interface to register</typeparam> /// <typeparam name="TInterface">The Interface to register</typeparam>
/// <typeparam name="TImplementation">The Type that implements the interface</typeparam> /// <typeparam name="TImplementation">The Type that implements the interface</typeparam>
/// <param name="lifestyle">The <see cref="Lifestyle"/> for this <see cref="ITypedRegistration{TInterface,TImplementation}"/></param> /// <param name="lifestyle">The <see cref="Lifestyle"/> for this <see cref="ITypedRegistration{TInterface,TImplementation}"/></param>
/// <returns>A new created <see cref="ITypedRegistration{TInterface,TImplementation}"/> with the given parameters</returns> /// <returns>A new created <see cref="ITypedRegistration{TInterface,TImplementation}"/> with the given parameters</returns>
public ITypedRegistration<TInterface, TImplementation> Register<TInterface, TImplementation>(Lifestyle lifestyle) where TImplementation : TInterface => public ITypedRegistration<TInterface, TImplementation> Register<TInterface, TImplementation>(Lifestyle lifestyle) where TImplementation : TInterface =>
new TypedRegistration<TInterface, TImplementation>(typeof(TInterface), typeof(TImplementation), lifestyle, _iocContainer); new TypedRegistration<TInterface, TImplementation>(typeof(TInterface), typeof(TImplementation), lifestyle, _iocContainer);
/// <summary> /// <summary>
/// Register an open generic Interface with an open generic Type that implements it and create a <see cref="IOpenGenericRegistration"/> /// Register an open generic Interface with an open generic Type that implements it and create a <see cref="IOpenGenericRegistration"/>
/// </summary> /// </summary>
/// <param name="tInterface">The open generic Interface to register</param> /// <param name="tInterface">The open generic Interface to register</param>
/// <param name="tImplementation">The open generic Type that implements the interface</param> /// <param name="tImplementation">The open generic Type that implements the interface</param>
/// <param name="lifestyle">The <see cref="Lifestyle"/> for this <see cref="IOpenGenericRegistration"/></param> /// <param name="lifestyle">The <see cref="Lifestyle"/> for this <see cref="IOpenGenericRegistration"/></param>
/// <returns>The created <see cref="IOpenGenericRegistration"/></returns> /// <returns>The created <see cref="IOpenGenericRegistration"/></returns>
public IOpenGenericRegistration Register(Type tInterface, Type tImplementation, Lifestyle lifestyle) => public IOpenGenericRegistration Register(Type tInterface, Type tImplementation, Lifestyle lifestyle) =>
new OpenGenericRegistration(tInterface, tImplementation, lifestyle, _iocContainer); new OpenGenericRegistration(tInterface, tImplementation, lifestyle, _iocContainer);
/// <summary> /// <summary>
/// Register multiple interfaces for a <see cref="Type"/> that implements them and create a <see cref="IMultipleRegistration{TInterface1,TInterface2}"/> /// Register multiple interfaces for a <see cref="Type"/> that implements them and create a <see cref="IMultipleRegistration{TInterface1,TInterface2}"/>
/// </summary> /// </summary>
/// <typeparam name="TInterface1">The base interface to register</typeparam> /// <typeparam name="TInterface1">The base interface to register</typeparam>
/// <typeparam name="TInterface2">A second interface to register</typeparam> /// <typeparam name="TInterface2">A second interface to register</typeparam>
/// <typeparam name="TImplementation">The <see cref="Type"/> that implements both interfaces</typeparam> /// <typeparam name="TImplementation">The <see cref="Type"/> that implements both interfaces</typeparam>
/// <param name="lifestyle">The <see cref="Lifestyle"/> for this <see cref="IRegistrationBase"/></param> /// <param name="lifestyle">The <see cref="Lifestyle"/> for this <see cref="IRegistrationBase"/></param>
/// <returns>The created <see cref="IMultipleRegistration{TInterface1,TInterface2}"/></returns> /// <returns>The created <see cref="IMultipleRegistration{TInterface1,TInterface2}"/></returns>
public IMultipleRegistration<TInterface1, TInterface2, TImplementation> Register<TInterface1, TInterface2, TImplementation>(Lifestyle lifestyle) where TImplementation : TInterface1, TInterface2 => public IMultipleRegistration<TInterface1, TInterface2, TImplementation> Register<TInterface1, TInterface2, TImplementation>(Lifestyle lifestyle) where TImplementation : TInterface1, TInterface2 =>
new MultipleRegistration<TInterface1, TInterface2, TImplementation>(typeof(TInterface1), typeof(TInterface2), typeof(TImplementation), lifestyle, _iocContainer); new MultipleRegistration<TInterface1, TInterface2, TImplementation>(typeof(TInterface1), typeof(TInterface2), typeof(TImplementation), lifestyle, _iocContainer);
/// <summary> /// <summary>
/// Register multiple interfaces for a <see cref="Type"/> that implements them and create a <see cref="IMultipleRegistration{TInterface1,TInterface2,TInterface3}"/> /// Register multiple interfaces for a <see cref="Type"/> that implements them and create a <see cref="IMultipleRegistration{TInterface1,TInterface2,TInterface3}"/>
/// </summary> /// </summary>
/// <typeparam name="TInterface1">The base interface to register</typeparam> /// <typeparam name="TInterface1">The base interface to register</typeparam>
/// <typeparam name="TInterface2">A second interface to register</typeparam> /// <typeparam name="TInterface2">A second interface to register</typeparam>
/// <typeparam name="TInterface3">A third interface to register</typeparam> /// <typeparam name="TInterface3">A third interface to register</typeparam>
/// <typeparam name="TImplementation">The <see cref="Type"/> that implements both interfaces</typeparam> /// <typeparam name="TImplementation">The <see cref="Type"/> that implements both interfaces</typeparam>
/// <param name="lifestyle">The <see cref="Lifestyle"/> for this <see cref="IRegistrationBase"/></param> /// <param name="lifestyle">The <see cref="Lifestyle"/> for this <see cref="IRegistrationBase"/></param>
/// <returns>The created <see cref="IMultipleRegistration{TInterface1,TInterface2,TInterface3}"/></returns> /// <returns>The created <see cref="IMultipleRegistration{TInterface1,TInterface2,TInterface3}"/></returns>
public IMultipleRegistration<TInterface1, TInterface2, TInterface3, TImplementation> Register<TInterface1, TInterface2, TInterface3, TImplementation>(Lifestyle lifestyle) where TImplementation : TInterface1, TInterface2, TInterface3 => public IMultipleRegistration<TInterface1, TInterface2, TInterface3, TImplementation> Register<TInterface1, TInterface2, TInterface3, TImplementation>(Lifestyle lifestyle) where TImplementation : TInterface1, TInterface2, TInterface3 =>
new MultipleRegistration<TInterface1, TInterface2, TInterface3, TImplementation>(typeof(TInterface1), typeof(TInterface2), typeof(TInterface3), typeof(TImplementation), lifestyle, _iocContainer); new MultipleRegistration<TInterface1, TInterface2, TInterface3, TImplementation>(typeof(TInterface1), typeof(TInterface2), typeof(TInterface3), typeof(TImplementation), lifestyle, _iocContainer);
/// <summary> /// <summary>
/// Register multiple interfaces for a <see cref="Type"/> that implements them and create a <see cref="IMultipleRegistration{TInterface1,TInterface2,TInterface3,TInterface4}"/> /// Register multiple interfaces for a <see cref="Type"/> that implements them and create a <see cref="IMultipleRegistration{TInterface1,TInterface2,TInterface3,TInterface4}"/>
/// </summary> /// </summary>
/// <typeparam name="TInterface1">The base interface to register</typeparam> /// <typeparam name="TInterface1">The base interface to register</typeparam>
/// <typeparam name="TInterface2">A second interface to register</typeparam> /// <typeparam name="TInterface2">A second interface to register</typeparam>
/// <typeparam name="TInterface3">A third interface to register</typeparam> /// <typeparam name="TInterface3">A third interface to register</typeparam>
/// <typeparam name="TInterface4">A fourth interface to register</typeparam> /// <typeparam name="TInterface4">A fourth interface to register</typeparam>
/// <typeparam name="TImplementation">The <see cref="Type"/> that implements both interfaces</typeparam> /// <typeparam name="TImplementation">The <see cref="Type"/> that implements both interfaces</typeparam>
/// <param name="lifestyle">The <see cref="Lifestyle"/> for this <see cref="IRegistrationBase"/></param> /// <param name="lifestyle">The <see cref="Lifestyle"/> for this <see cref="IRegistrationBase"/></param>
/// <returns>The created <see cref="IMultipleRegistration{TInterface1,TInterface2,TInterface3,TInterface4}"/></returns> /// <returns>The created <see cref="IMultipleRegistration{TInterface1,TInterface2,TInterface3,TInterface4}"/></returns>
public IMultipleRegistration<TInterface1, TInterface2, TInterface3, TInterface4, TImplementation> Register<TInterface1, TInterface2, TInterface3, TInterface4, TImplementation>(Lifestyle lifestyle) where TImplementation : TInterface1, TInterface2, TInterface3, TInterface4 => public IMultipleRegistration<TInterface1, TInterface2, TInterface3, TInterface4, TImplementation> Register<TInterface1, TInterface2, TInterface3, TInterface4, TImplementation>(Lifestyle lifestyle) where TImplementation : TInterface1, TInterface2, TInterface3, TInterface4 =>
new MultipleRegistration<TInterface1, TInterface2, TInterface3, TInterface4, TImplementation>(typeof(TInterface1), typeof(TInterface2), typeof(TInterface3), typeof(TInterface4), typeof(TImplementation), lifestyle, _iocContainer); new MultipleRegistration<TInterface1, TInterface2, TInterface3, TInterface4, TImplementation>(typeof(TInterface1), typeof(TInterface2), typeof(TInterface3), typeof(TInterface4), typeof(TImplementation), lifestyle, _iocContainer);
/// <summary> /// <summary>
/// Register multiple interfaces for a <see cref="Type"/> that implements them and create a <see cref="IMultipleRegistration{TInterface1,TInterface2,TInterface3,TInterface4,TInterface5}"/> /// Register multiple interfaces for a <see cref="Type"/> that implements them and create a <see cref="IMultipleRegistration{TInterface1,TInterface2,TInterface3,TInterface4,TInterface5}"/>
/// </summary> /// </summary>
/// <typeparam name="TInterface1">The base interface to register</typeparam> /// <typeparam name="TInterface1">The base interface to register</typeparam>
/// <typeparam name="TInterface2">A second interface to register</typeparam> /// <typeparam name="TInterface2">A second interface to register</typeparam>
/// <typeparam name="TInterface3">A third interface to register</typeparam> /// <typeparam name="TInterface3">A third interface to register</typeparam>
/// <typeparam name="TInterface4">A fourth interface to register</typeparam> /// <typeparam name="TInterface4">A fourth interface to register</typeparam>
/// <typeparam name="TInterface5">A fifth interface to register</typeparam> /// <typeparam name="TInterface5">A fifth interface to register</typeparam>
/// <typeparam name="TImplementation">The <see cref="Type"/> that implements both interfaces</typeparam> /// <typeparam name="TImplementation">The <see cref="Type"/> that implements both interfaces</typeparam>
/// <param name="lifestyle">The <see cref="Lifestyle"/> for this <see cref="IRegistrationBase"/></param> /// <param name="lifestyle">The <see cref="Lifestyle"/> for this <see cref="IRegistrationBase"/></param>
/// <returns>The created <see cref="IMultipleRegistration{TInterface1,TInterface2,TInterface3,TInterface4,TInterface5}"/></returns> /// <returns>The created <see cref="IMultipleRegistration{TInterface1,TInterface2,TInterface3,TInterface4,TInterface5}"/></returns>
public IMultipleRegistration<TInterface1, TInterface2, TInterface3, TInterface4, TInterface5, TImplementation> Register<TInterface1, TInterface2, TInterface3, TInterface4, TInterface5, TImplementation>(Lifestyle lifestyle) where TImplementation : TInterface1, TInterface2, TInterface3, TInterface4, TInterface5 => public IMultipleRegistration<TInterface1, TInterface2, TInterface3, TInterface4, TInterface5, TImplementation> Register<TInterface1, TInterface2, TInterface3, TInterface4, TInterface5, TImplementation>(Lifestyle lifestyle) where TImplementation : TInterface1, TInterface2, TInterface3, TInterface4, TInterface5 =>
new MultipleRegistration<TInterface1, TInterface2, TInterface3, TInterface4, TInterface5, TImplementation>(typeof(TInterface1), typeof(TInterface2), typeof(TInterface3), typeof(TInterface4), typeof(TInterface5), typeof(TImplementation), lifestyle, _iocContainer); new MultipleRegistration<TInterface1, TInterface2, TInterface3, TInterface4, TInterface5, TImplementation>(typeof(TInterface1), typeof(TInterface2), typeof(TInterface3), typeof(TInterface4), typeof(TInterface5), typeof(TImplementation), lifestyle, _iocContainer);
/// <summary> /// <summary>
/// Register a <see cref="Type"/> without an interface and create a <see cref="ISingleTypeRegistration{TInterface}"/> /// Register a <see cref="Type"/> without an interface and create a <see cref="ISingleTypeRegistration{TInterface}"/>
/// </summary> /// </summary>
/// <typeparam name="T">The <see cref="Type"/> to register</typeparam> /// <typeparam name="T">The <see cref="Type"/> to register</typeparam>
/// <param name="lifestyle">The <see cref="Lifestyle"/> for this <see cref="ISingleTypeRegistration{TInterface}"/></param> /// <param name="lifestyle">The <see cref="Lifestyle"/> for this <see cref="ISingleTypeRegistration{TInterface}"/></param>
/// <returns>A new created <see cref="ISingleTypeRegistration{TInterface}"/> with the given parameters</returns> /// <returns>A new created <see cref="ISingleTypeRegistration{TInterface}"/> with the given parameters</returns>
public ISingleTypeRegistration<T> Register<T>(Lifestyle lifestyle) => new SingleTypeRegistration<T>(typeof(T), lifestyle, _iocContainer); public ISingleTypeRegistration<T> Register<T>(Lifestyle lifestyle) => new SingleTypeRegistration<T>(typeof(T), lifestyle, _iocContainer);
/// <summary> /// <summary>
/// Register an Interface with a Type that implements it as a multiton and create a <see cref="IMultitonRegistration{TInterface,TImplementation}"/> /// Register an Interface with a Type that implements it as a multiton and create a <see cref="IMultitonRegistration{TInterface,TImplementation}"/>
/// </summary> /// </summary>
/// <typeparam name="TInterface">The Interface to register</typeparam> /// <typeparam name="TInterface">The Interface to register</typeparam>
/// <typeparam name="TImplementation">The Type that implements the interface</typeparam> /// <typeparam name="TImplementation">The Type that implements the interface</typeparam>
/// <typeparam name="TScope">The Type of the multiton scope</typeparam> /// <typeparam name="TScope">The Type of the multiton scope</typeparam>
/// <returns>A new created <see cref="IMultitonRegistration{TInterface,TImplementation}"/> with the given parameters</returns> /// <returns>A new created <see cref="IMultitonRegistration{TInterface,TImplementation}"/> with the given parameters</returns>
public IMultitonRegistration<TInterface, TImplementation> RegisterMultiton<TInterface, TImplementation, TScope>() where TImplementation : TInterface => public IMultitonRegistration<TInterface, TImplementation> RegisterMultiton<TInterface, TImplementation, TScope>() where TImplementation : TInterface =>
new MultitonRegistration<TInterface, TImplementation>(typeof(TInterface), typeof(TImplementation), typeof(TScope), _iocContainer); new MultitonRegistration<TInterface, TImplementation>(typeof(TInterface), typeof(TImplementation), typeof(TScope), _iocContainer);
/// <summary> /// <summary>
/// Register multiple interfaces for a <see cref="Type"/> that implements them as a multiton /// Register multiple interfaces for a <see cref="Type"/> that implements them as a multiton
/// </summary> /// </summary>
/// <typeparam name="TInterface1">The base interface to register</typeparam> /// <typeparam name="TInterface1">The base interface to register</typeparam>
/// <typeparam name="TInterface2">A second interface to register</typeparam> /// <typeparam name="TInterface2">A second interface to register</typeparam>
/// <typeparam name="TImplementation">The Type that implements the interface</typeparam> /// <typeparam name="TImplementation">The Type that implements the interface</typeparam>
/// <typeparam name="TScope">The Type of the multiton scope</typeparam> /// <typeparam name="TScope">The Type of the multiton scope</typeparam>
/// <returns>A new created <see cref="IMultipleMultitonRegistration{TInterface1,TInterface2,TImplementation}"/> with the given parameters</returns> /// <returns>A new created <see cref="IMultipleMultitonRegistration{TInterface1,TInterface2,TImplementation}"/> with the given parameters</returns>
public IMultipleMultitonRegistration<TInterface1, TInterface2, TImplementation> RegisterMultiton<TInterface1, TInterface2, TImplementation, TScope>() where TImplementation : TInterface1, TInterface2 => public IMultipleMultitonRegistration<TInterface1, TInterface2, TImplementation> RegisterMultiton<TInterface1, TInterface2, TImplementation, TScope>() where TImplementation : TInterface1, TInterface2 =>
new MultipleMultitonRegistration<TInterface1, TInterface2, TImplementation>(typeof(TInterface1), typeof(TInterface2), typeof(TImplementation), typeof(TScope), _iocContainer); new MultipleMultitonRegistration<TInterface1, TInterface2, TImplementation>(typeof(TInterface1), typeof(TInterface2), typeof(TImplementation), typeof(TScope), _iocContainer);
/// <summary> /// <summary>
/// Register an Interface as an abstract typed factory and create a <see cref="ITypedFactoryRegistration{TFactory}"/> /// Register an Interface as an abstract typed factory and create a <see cref="ITypedFactoryRegistration{TFactory}"/>
/// </summary> /// </summary>
/// <typeparam name="TFactory">The abstract typed factory to register</typeparam> /// <typeparam name="TFactory">The abstract typed factory to register</typeparam>
/// <returns>A new created <see cref="ITypedFactoryRegistration{TFactory}"/> with the given parameters</returns> /// <returns>A new created <see cref="ITypedFactoryRegistration{TFactory}"/> with the given parameters</returns>
public ITypedFactoryRegistration<TFactory> RegisterFactory<TFactory>(ITypedFactory<TFactory> factory) => new TypedFactoryRegistration<TFactory>(factory); public ITypedFactoryRegistration<TFactory> RegisterFactory<TFactory>(ITypedFactory<TFactory> factory) => new TypedFactoryRegistration<TFactory>(factory);
}
} }

@ -6,56 +6,55 @@ using System;
using LightweightIocContainer.Interfaces; using LightweightIocContainer.Interfaces;
using LightweightIocContainer.Interfaces.Registrations; using LightweightIocContainer.Interfaces.Registrations;
namespace LightweightIocContainer.Registrations namespace LightweightIocContainer.Registrations;
/// <summary>
/// The <see cref="IRegistration"/> to register either only an interface or only a <see cref="Type"/>
/// </summary>
/// <typeparam name="T">The <see cref="Type"/> of the <see cref="IRegistration"/></typeparam>
internal class SingleTypeRegistration<T> : RegistrationBase, ISingleTypeRegistration<T>
{ {
/// <summary> /// <summary>
/// The <see cref="IRegistration"/> to register either only an interface or only a <see cref="Type"/> /// The <see cref="IRegistration"/> to register either only an interface or only a <see cref="Type"/>
/// </summary> /// </summary>
/// <typeparam name="T">The <see cref="Type"/> of the <see cref="IRegistration"/></typeparam> /// <param name="interfaceType">The <see cref="Type"/> of the interface or <see cref="Type"/></param>
internal class SingleTypeRegistration<T> : RegistrationBase, ISingleTypeRegistration<T> /// <param name="lifestyle">The <see cref="Lifestyle"/> of the <see cref="RegistrationBase"/></param>
/// <param name="container">The current instance of the <see cref="IIocContainer"/></param>
public SingleTypeRegistration(Type interfaceType, Lifestyle lifestyle, IocContainer container)
: base(interfaceType, lifestyle, container)
{ {
/// <summary>
/// The <see cref="IRegistration"/> to register either only an interface or only a <see cref="Type"/>
/// </summary>
/// <param name="interfaceType">The <see cref="Type"/> of the interface or <see cref="Type"/></param>
/// <param name="lifestyle">The <see cref="Lifestyle"/> of the <see cref="RegistrationBase"/></param>
/// <param name="container">The current instance of the <see cref="IIocContainer"/></param>
public SingleTypeRegistration(Type interfaceType, Lifestyle lifestyle, IocContainer container)
: base(interfaceType, lifestyle, container)
{
} }
/// <summary> /// <summary>
/// <see cref="Func{T,TResult}"/> that is invoked instead of creating an instance of this <see cref="Type"/> the default way /// <see cref="Func{T,TResult}"/> that is invoked instead of creating an instance of this <see cref="Type"/> the default way
/// </summary> /// </summary>
public Func<IIocResolver, T>? FactoryMethod { get; private set; } public Func<IIocResolver, T>? FactoryMethod { get; private set; }
/// <summary> /// <summary>
/// Pass a <see cref="Func{T,TResult}"/> that will be invoked instead of creating an instance of this <see cref="Type"/> the default way /// Pass a <see cref="Func{T,TResult}"/> that will be invoked instead of creating an instance of this <see cref="Type"/> the default way
/// </summary> /// </summary>
/// <param name="factoryMethod">The <see cref="Func{T,TResult}"/></param> /// <param name="factoryMethod">The <see cref="Func{T,TResult}"/></param>
/// <returns>The current instance of this <see cref="IRegistration"/></returns> /// <returns>The current instance of this <see cref="IRegistration"/></returns>
public ISingleTypeRegistration<T> WithFactoryMethod(Func<IIocResolver, T> factoryMethod) public ISingleTypeRegistration<T> WithFactoryMethod(Func<IIocResolver, T> factoryMethod)
{ {
FactoryMethod = factoryMethod; FactoryMethod = factoryMethod;
return this; return this;
} }
public override bool Equals(object? obj) public override bool Equals(object? obj)
{ {
if (obj is not SingleTypeRegistration<T> singleTypeRegistration) if (obj is not SingleTypeRegistration<T> singleTypeRegistration)
return false; return false;
if (FactoryMethod == null && singleTypeRegistration.FactoryMethod != null) if (FactoryMethod == null && singleTypeRegistration.FactoryMethod != null)
return false; return false;
if (FactoryMethod != null && singleTypeRegistration.FactoryMethod == null) if (FactoryMethod != null && singleTypeRegistration.FactoryMethod == null)
return false; return false;
return base.Equals(obj); return base.Equals(obj);
}
public override int GetHashCode() => base.GetHashCode();
} }
public override int GetHashCode() => base.GetHashCode();
} }

@ -6,34 +6,33 @@ using System;
using LightweightIocContainer.Interfaces.Factories; using LightweightIocContainer.Interfaces.Factories;
using LightweightIocContainer.Interfaces.Registrations; using LightweightIocContainer.Interfaces.Registrations;
namespace LightweightIocContainer.Registrations namespace LightweightIocContainer.Registrations;
/// <summary>
/// The registration that is used to register an abstract typed factory
/// </summary>
/// <typeparam name="TFactory">The <see cref="Type"/> of the abstract typed factory</typeparam>
internal class TypedFactoryRegistration<TFactory> : ITypedFactoryRegistration<TFactory>
{ {
/// <summary> /// <summary>
/// The registration that is used to register an abstract typed factory /// The registration that is used to register an abstract typed factory
/// </summary> /// </summary>
/// <typeparam name="TFactory">The <see cref="Type"/> of the abstract typed factory</typeparam> /// <param name="factory">The <see cref="ITypedFactory{TFactory}"/> for this <see cref="IRegistration"/></param>
internal class TypedFactoryRegistration<TFactory> : ITypedFactoryRegistration<TFactory> public TypedFactoryRegistration(ITypedFactory<TFactory> factory) => Factory = factory;
{
/// <summary>
/// The registration that is used to register an abstract typed factory
/// </summary>
/// <param name="factory">The <see cref="ITypedFactory{TFactory}"/> for this <see cref="IRegistration"/></param>
public TypedFactoryRegistration(ITypedFactory<TFactory> factory) => Factory = factory;
/// <summary> /// <summary>
/// The <see cref="Type"/> of the factory that is registered with this <see cref="IRegistration"/> /// The <see cref="Type"/> of the factory that is registered with this <see cref="IRegistration"/>
/// </summary> /// </summary>
public Type InterfaceType => typeof(TFactory); public Type InterfaceType => typeof(TFactory);
/// <summary> /// <summary>
/// The class that contains the implemented abstract factory of this <see cref="TypedFactoryRegistration{TFactory}"/> /// The class that contains the implemented abstract factory of this <see cref="TypedFactoryRegistration{TFactory}"/>
/// </summary> /// </summary>
public ITypedFactory<TFactory> Factory { get; } public ITypedFactory<TFactory> Factory { get; }
public override bool Equals(object? obj) => obj is TypedFactoryRegistration<TFactory> factoryRegistration && public override bool Equals(object? obj) => obj is TypedFactoryRegistration<TFactory> factoryRegistration &&
Factory.CreateMethods.Count == factoryRegistration.Factory.CreateMethods.Count && Factory.CreateMethods.Count == factoryRegistration.Factory.CreateMethods.Count &&
InterfaceType == factoryRegistration.InterfaceType; InterfaceType == factoryRegistration.InterfaceType;
public override int GetHashCode() => HashCode.Combine(InterfaceType); public override int GetHashCode() => HashCode.Combine(InterfaceType);
}
} }

@ -8,74 +8,73 @@ using LightweightIocContainer.Interfaces.Installers;
using LightweightIocContainer.Interfaces.Registrations; using LightweightIocContainer.Interfaces.Registrations;
using LightweightIocContainer.Interfaces.Registrations.Fluent; using LightweightIocContainer.Interfaces.Registrations.Fluent;
namespace LightweightIocContainer.Registrations namespace LightweightIocContainer.Registrations;
/// <summary>
/// A <see cref="IRegistrationBase"/> that implements a <see cref="Type"/>
/// </summary>
internal class TypedRegistration<TInterface, TImplementation> : RegistrationBase, ITypedRegistration<TInterface, TImplementation> where TImplementation : TInterface
{ {
/// <summary> /// <summary>
/// A <see cref="IRegistrationBase"/> that implements a <see cref="Type"/> /// A <see cref="IRegistrationBase"/> that implements a <see cref="Type"/>
/// </summary> /// </summary>
internal class TypedRegistration<TInterface, TImplementation> : RegistrationBase, ITypedRegistration<TInterface, TImplementation> where TImplementation : TInterface /// <param name="interfaceType">The <see cref="Type"/> of the interface</param>
{ /// <param name="implementationType">The <see cref="Type"/> of the implementation type</param>
/// <summary> /// <param name="lifestyle">The <see cref="Lifestyle"/> of this <see cref="IRegistrationBase"/></param>
/// A <see cref="IRegistrationBase"/> that implements a <see cref="Type"/> /// <param name="container">The current instance of the <see cref="IIocContainer"/></param>
/// </summary> public TypedRegistration(Type interfaceType, Type implementationType, Lifestyle lifestyle, IocContainer container)
/// <param name="interfaceType">The <see cref="Type"/> of the interface</param> : base(interfaceType, lifestyle, container) =>
/// <param name="implementationType">The <see cref="Type"/> of the implementation type</param> ImplementationType = implementationType;
/// <param name="lifestyle">The <see cref="Lifestyle"/> of this <see cref="IRegistrationBase"/></param>
/// <param name="container">The current instance of the <see cref="IIocContainer"/></param>
public TypedRegistration(Type interfaceType, Type implementationType, Lifestyle lifestyle, IocContainer container)
: base(interfaceType, lifestyle, container) =>
ImplementationType = implementationType;
/// <summary> /// <summary>
/// The <see cref="Type"/> that implements the <see cref="IRegistration.InterfaceType"/> that is registered with this <see cref="IRegistrationBase"/> /// The <see cref="Type"/> that implements the <see cref="IRegistration.InterfaceType"/> that is registered with this <see cref="IRegistrationBase"/>
/// </summary> /// </summary>
public Type ImplementationType { get; } public Type ImplementationType { get; }
/// <summary> /// <summary>
/// This <see cref="Action"/> is invoked when an instance of this type is created. /// This <see cref="Action"/> is invoked when an instance of this type is created.
/// <para>Can be set in the <see cref="IIocInstaller"/> by calling <see cref="IOnCreate{TInterface,TImplementation}.OnCreate"/></para> /// <para>Can be set in the <see cref="IIocInstaller"/> by calling <see cref="IOnCreate{TInterface,TImplementation}.OnCreate"/></para>
/// </summary> /// </summary>
private Action<object?>? OnCreateAction { get; set; } private Action<object?>? OnCreateAction { get; set; }
/// <summary> /// <summary>
/// This <see cref="Action"/> is invoked when an instance of this type is created. /// This <see cref="Action"/> is invoked when an instance of this type is created.
/// <para>Can be set in the <see cref="IIocInstaller"/> by calling <see cref="IOnCreate{TInterface,TImplementation}.OnCreate"/></para> /// <para>Can be set in the <see cref="IIocInstaller"/> by calling <see cref="IOnCreate{TInterface,TImplementation}.OnCreate"/></para>
/// </summary> /// </summary>
Action<object?>? IOnCreate.OnCreateAction => OnCreateAction; Action<object?>? IOnCreate.OnCreateAction => OnCreateAction;
/// <summary> /// <summary>
/// Pass an <see cref="Action{T}"/> that will be invoked when an instance of this type is created /// Pass an <see cref="Action{T}"/> that will be invoked when an instance of this type is created
/// </summary> /// </summary>
/// <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="ITypedRegistration{TInterface,TImplementation}"/></returns> /// <returns>The current instance of this <see cref="ITypedRegistration{TInterface,TImplementation}"/></returns>
public virtual ITypedRegistration<TInterface, TImplementation> OnCreate(Action<TImplementation?> action) public virtual ITypedRegistration<TInterface, TImplementation> OnCreate(Action<TImplementation?> action)
{ {
OnCreateAction = a => action((TImplementation?) a); OnCreateAction = a => action((TImplementation?) a);
return this; return this;
} }
/// <summary> /// <summary>
/// Validate the <see cref="DisposeStrategy"/> for the <see cref="ImplementationType"/> and <see cref="Lifestyle"/> /// Validate the <see cref="DisposeStrategy"/> for the <see cref="ImplementationType"/> and <see cref="Lifestyle"/>
/// </summary> /// </summary>
protected override void ValidateDisposeStrategy() => ValidateDisposeStrategy(ImplementationType); protected override void ValidateDisposeStrategy() => ValidateDisposeStrategy(ImplementationType);
public override bool Equals(object? obj) public override bool Equals(object? obj)
{ {
if (obj is not TypedRegistration<TInterface, TImplementation> typedRegistration) if (obj is not TypedRegistration<TInterface, TImplementation> typedRegistration)
return false; return false;
if (!base.Equals(obj)) if (!base.Equals(obj))
return false; return false;
if (OnCreateAction == null && typedRegistration.OnCreateAction != null) if (OnCreateAction == null && typedRegistration.OnCreateAction != null)
return false; return false;
if (OnCreateAction != null && typedRegistration.OnCreateAction == null) if (OnCreateAction != null && typedRegistration.OnCreateAction == null)
return false; return false;
return ImplementationType == typedRegistration.ImplementationType; return ImplementationType == typedRegistration.ImplementationType;
}
public override int GetHashCode() => HashCode.Combine(base.GetHashCode(), ImplementationType);
} }
public override int GetHashCode() => HashCode.Combine(base.GetHashCode(), ImplementationType);
} }

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

@ -6,33 +6,32 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using LightweightIocContainer.Interfaces.Registrations; using LightweightIocContainer.Interfaces.Registrations;
namespace LightweightIocContainer.ResolvePlaceholders 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 : IInternalToBeResolvedPlaceholder
{ {
/// <summary> public InternalToBeResolvedPlaceholder(Type resolvedType, IRegistration resolvedRegistration, List<object?>? parameters)
/// An internal placeholder that is used to hold types that need to be resolved during the resolving process
/// </summary>
internal class InternalToBeResolvedPlaceholder : IInternalToBeResolvedPlaceholder
{ {
public InternalToBeResolvedPlaceholder(Type resolvedType, IRegistration resolvedRegistration, List<object?>? parameters) ResolvedType = resolvedType;
{ ResolvedRegistration = resolvedRegistration;
ResolvedType = resolvedType; Parameters = parameters;
ResolvedRegistration = resolvedRegistration; }
Parameters = parameters;
}
/// <summary> /// <summary>
/// The <see cref="Type"/> to be resolved /// The <see cref="Type"/> to be resolved
/// </summary> /// </summary>
public Type ResolvedType { get; } public Type ResolvedType { get; }
/// <summary> /// <summary>
/// The <see cref="IRegistration"/> to be resolved /// The <see cref="IRegistration"/> to be resolved
/// </summary> /// </summary>
public IRegistration ResolvedRegistration { get; } public IRegistration ResolvedRegistration { get; }
/// <summary> /// <summary>
/// The parameters needed to resolve the <see cref="ResolvedRegistration"/> /// The parameters needed to resolve the <see cref="ResolvedRegistration"/>
/// </summary> /// </summary>
public List<object?>? Parameters { get; } public List<object?>? Parameters { get; }
}
} }

@ -4,15 +4,14 @@
using System; using System;
namespace LightweightIocContainer namespace LightweightIocContainer;
internal static class TypeExtension
{ {
internal static class TypeExtension /// <summary>
{ /// Returns the default value for a given <see cref="Type"/>
/// <summary> /// </summary>
/// Returns the default value for a given <see cref="Type"/> /// <param name="type">The given <see cref="Type"/></param>
/// </summary> /// <returns>The default value for the given <see cref="Type"/></returns>
/// <param name="type">The given <see cref="Type"/></param> public static object? GetDefault(this Type type) => type.IsValueType ? Activator.CreateInstance(type) : null;
/// <returns>The default value for the given <see cref="Type"/></returns>
public static object? GetDefault(this Type type) => type.IsValueType ? Activator.CreateInstance(type) : null;
}
} }

@ -9,98 +9,97 @@ using LightweightIocContainer.Interfaces.Registrations;
using LightweightIocContainer.Interfaces.Registrations.Fluent; using LightweightIocContainer.Interfaces.Registrations.Fluent;
using Moq; using Moq;
namespace LightweightIocContainer.Validation namespace LightweightIocContainer.Validation;
/// <summary>
/// Validator for your <see cref="IocContainer"/> to check if everything can be resolved with your current setup
/// </summary>
public class IocValidator
{ {
private readonly IocContainer _iocContainer;
private readonly List<(Type type, object? parameter)> _parameters;
/// <summary> /// <summary>
/// Validator for your <see cref="IocContainer"/> to check if everything can be resolved with your current setup /// Validator for your <see cref="IocContainer"/> to check if everything can be resolved with your current setup
/// </summary> /// </summary>
public class IocValidator /// <param name="iocContainer">The <see cref="IocContainer"/></param>
public IocValidator(IocContainer iocContainer)
{ {
private readonly IocContainer _iocContainer; _iocContainer = iocContainer;
private readonly List<(Type type, object? parameter)> _parameters; _parameters = new List<(Type, object?)>();
}
/// <summary>
/// Validator for your <see cref="IocContainer"/> to check if everything can be resolved with your current setup
/// </summary>
/// <param name="iocContainer">The <see cref="IocContainer"/></param>
public IocValidator(IocContainer iocContainer)
{
_iocContainer = iocContainer;
_parameters = new List<(Type, object?)>();
}
/// <summary> /// <summary>
/// Add parameters that can't be default for your type to be created successfully /// Add parameters that can't be default for your type to be created successfully
/// </summary> /// </summary>
/// <param name="parameter">The new value of the parameter</param> /// <param name="parameter">The new value of the parameter</param>
/// <typeparam name="TInterface">The <see cref="Type"/> of your registered interface</typeparam> /// <typeparam name="TInterface">The <see cref="Type"/> of your registered interface</typeparam>
/// <typeparam name="TParameter">The <see cref="Type"/> of your <paramref name="parameter"></paramref></typeparam> /// <typeparam name="TParameter">The <see cref="Type"/> of your <paramref name="parameter"></paramref></typeparam>
public void AddParameter<TInterface, TParameter>(TParameter parameter) => _parameters.Add((typeof(TInterface), parameter)); public void AddParameter<TInterface, TParameter>(TParameter parameter) => _parameters.Add((typeof(TInterface), parameter));
/// <summary> /// <summary>
/// Validates your given <see cref="IocContainer"/> and checks if everything can be resolved with the current setup /// Validates your given <see cref="IocContainer"/> and checks if everything can be resolved with the current setup
/// <exception cref="AggregateException">Collection of all exceptions that are thrown during validation</exception> /// <exception cref="AggregateException">Collection of all exceptions that are thrown during validation</exception>
/// </summary> /// </summary>
public void Validate() public void Validate()
{ {
List<Exception> validationExceptions = new(); List<Exception> validationExceptions = new();
foreach (IRegistration registration in _iocContainer.Registrations) foreach (IRegistration registration in _iocContainer.Registrations)
{ {
var definedParameters = _parameters.Where(p => p.type == registration.InterfaceType); var definedParameters = _parameters.Where(p => p.type == registration.InterfaceType);
if (registration is IWithFactoryInternal { Factory: { } } withFactoryRegistration) if (registration is IWithFactoryInternal { Factory: { } } withFactoryRegistration)
{ {
(from createMethod in withFactoryRegistration.Factory.CreateMethods (from createMethod in withFactoryRegistration.Factory.CreateMethods
select createMethod.GetParameters().Select(p => p.ParameterType) select createMethod.GetParameters().Select(p => p.ParameterType)
into parameterTypes into parameterTypes
select (from parameterType in parameterTypes select (from parameterType in parameterTypes
let definedParameter = definedParameters let definedParameter = definedParameters
.FirstOrDefault(p => parameterType.IsInstanceOfType(p.parameter)) .FirstOrDefault(p => parameterType.IsInstanceOfType(p.parameter))
select definedParameter == default ? GetMockOrDefault(parameterType) : definedParameter.parameter).ToArray()) select definedParameter == default ? GetMockOrDefault(parameterType) : definedParameter.parameter).ToArray())
.ToList() .ToList()
.ForEach(p => TryResolve(registration.InterfaceType, p, validationExceptions, true)); .ForEach(p => TryResolve(registration.InterfaceType, p, validationExceptions, true));
}
else
{
object?[] arguments = definedParameters.Select(p => p.parameter).ToArray();
TryResolve(registration.InterfaceType, arguments, validationExceptions);
}
} }
else
if (validationExceptions.Any())
throw new AggregateException("Validation failed.", validationExceptions);
}
private void TryResolve(Type type, object?[]? arguments, List<Exception> validationExceptions, bool isFactoryResolve = false)
{
try
{ {
_iocContainer.TryResolveNonGeneric(type, arguments, null, isFactoryResolve); object?[] arguments = definedParameters.Select(p => p.parameter).ToArray();
} TryResolve(registration.InterfaceType, arguments, validationExceptions);
catch (Exception exception)
{
validationExceptions.Add(exception);
} }
} }
private T GetMock<T>() where T : class => new Mock<T>().Object; if (validationExceptions.Any())
private object? GetMockOrDefault(Type type) throw new AggregateException("Validation failed.", validationExceptions);
}
private void TryResolve(Type type, object?[]? arguments, List<Exception> validationExceptions, bool isFactoryResolve = false)
{
try
{ {
if (type.IsValueType) _iocContainer.TryResolveNonGeneric(type, arguments, null, isFactoryResolve);
return Activator.CreateInstance(type); }
catch (Exception exception)
{
validationExceptions.Add(exception);
}
}
if (type == typeof(string)) private T GetMock<T>() where T : class => new Mock<T>().Object;
return string.Empty; private object? GetMockOrDefault(Type type)
{
if (type.IsValueType)
return Activator.CreateInstance(type);
if (type == typeof(string))
return string.Empty;
try try
{ {
return GenericMethodCaller.CallPrivate(this, nameof(GetMock), type); return GenericMethodCaller.CallPrivate(this, nameof(GetMock), type);
} }
catch (Exception) catch (Exception)
{ {
return null; return null;
}
} }
} }
} }

@ -6,41 +6,40 @@ using System;
using LightweightIocContainer; using LightweightIocContainer;
using NUnit.Framework; using NUnit.Framework;
namespace Test.LightweightIocContainer namespace Test.LightweightIocContainer;
[TestFixture]
public class ActionExtensionTest
{ {
[TestFixture] private interface IBar
public class ActionExtensionTest
{ {
private interface IBar void Throw();
{ }
void Throw();
}
private interface IFoo : IBar private interface IFoo : IBar
{ {
} }
private class Foo : IFoo private class Foo : IFoo
{ {
public void Throw() => throw new Exception(); public void Throw() => throw new Exception();
} }
[Test] [Test]
public void TestConvert() public void TestConvert()
{ {
Action<IBar> barAction = bar => bar.Throw(); Action<IBar> barAction = bar => bar.Throw();
Action<IFoo> action = barAction.Convert<IFoo, IBar>(); Action<IFoo> action = barAction.Convert<IFoo, IBar>();
Assert.Throws<Exception>(() => action(new Foo())); Assert.Throws<Exception>(() => action(new Foo()));
} }
[Test] [Test]
public void TestConvertActionNull() public void TestConvertActionNull()
{ {
Action<IBar> barAction = null; Action<IBar> barAction = null;
Assert.Null(barAction.Convert<IFoo, IBar>()); Assert.Null(barAction.Convert<IFoo, IBar>());
}
} }
} }

@ -14,65 +14,64 @@ using LightweightIocContainer.Interfaces.Registrations;
using Moq; using Moq;
using NUnit.Framework; using NUnit.Framework;
namespace Test.LightweightIocContainer namespace Test.LightweightIocContainer;
[TestFixture]
public class AssemblyInstallerTest
{ {
[TestFixture] [UsedImplicitly]
public class AssemblyInstallerTest public class TestInstaller : IIocInstaller
{ {
[UsedImplicitly] public void Install(IRegistrationCollector registration) => registration.Add<Mock<IRegistration>>();
public class TestInstaller : IIocInstaller }
{
public void Install(IRegistrationCollector registration) => registration.Add<Mock<IRegistration>>();
}
[UsedImplicitly] [UsedImplicitly]
public class AssemblyWrapper : Assembly public class AssemblyWrapper : Assembly
{ {
} }
[Test] [Test]
public void TestInstall() public void TestInstall()
{
List<Type> types = new()
{ {
List<Type> types = new() typeof(object),
{ typeof(TestInstaller)
typeof(object), };
typeof(TestInstaller)
};
Mock<AssemblyWrapper> assemblyMock = new(); Mock<AssemblyWrapper> assemblyMock = new();
assemblyMock.Setup(a => a.GetTypes()).Returns(types.ToArray); assemblyMock.Setup(a => a.GetTypes()).Returns(types.ToArray);
Mock<IRegistrationCollector> registrationCollectorMock = new(); Mock<IRegistrationCollector> registrationCollectorMock = new();
AssemblyInstaller assemblyInstaller = new(assemblyMock.Object); AssemblyInstaller assemblyInstaller = new(assemblyMock.Object);
assemblyInstaller.Install(registrationCollectorMock.Object); assemblyInstaller.Install(registrationCollectorMock.Object);
registrationCollectorMock.Verify(r => r.Add<It.IsSubtype<Mock<IRegistration>>>(It.IsAny<Lifestyle>()), Times.Once); registrationCollectorMock.Verify(r => r.Add<It.IsSubtype<Mock<IRegistration>>>(It.IsAny<Lifestyle>()), Times.Once);
} }
[Test] [Test]
public void TestFromAssemblyThis() public void TestFromAssemblyThis()
{ {
IIocContainer iocContainer = new IocContainer(); IIocContainer iocContainer = new IocContainer();
iocContainer.Install(FromAssembly.This()); iocContainer.Install(FromAssembly.This());
} }
[Test] [Test]
public void TestFromAssemblyInstance() public void TestFromAssemblyInstance()
{
List<Type> types = new()
{ {
List<Type> types = new() typeof(object),
{ typeof(TestInstaller)
typeof(object), };
typeof(TestInstaller)
};
Mock<AssemblyWrapper> assemblyMock = new(); Mock<AssemblyWrapper> assemblyMock = new();
assemblyMock.Setup(a => a.GetTypes()).Returns(types.ToArray); assemblyMock.Setup(a => a.GetTypes()).Returns(types.ToArray);
IIocContainer iocContainer = new IocContainer(); IIocContainer iocContainer = new IocContainer();
iocContainer.Install(FromAssembly.Instance(assemblyMock.Object)); iocContainer.Install(FromAssembly.Instance(assemblyMock.Object));
}
} }
} }

@ -9,94 +9,93 @@ using LightweightIocContainer;
using Moq; using Moq;
using NUnit.Framework; using NUnit.Framework;
namespace Test.LightweightIocContainer namespace Test.LightweightIocContainer;
[TestFixture]
public class EnumerableExtensionTest
{ {
[TestFixture] private class ListObject
public class EnumerableExtensionTest
{ {
private class ListObject public int Index { get; set; }
{ }
public int Index { get; set; }
}
private class Given : ListObject private class Given : ListObject
{ {
} }
[UsedImplicitly] [UsedImplicitly]
public interface ITest public interface ITest
{ {
void DoSomething(); void DoSomething();
} }
[Test] [Test]
[SuppressMessage("ReSharper", "CollectionNeverUpdated.Local")] [SuppressMessage("ReSharper", "CollectionNeverUpdated.Local")]
public void TestFirstOrGivenNoPredicateEmpty() public void TestFirstOrGivenNoPredicateEmpty()
{ {
List<ListObject> list = new(); List<ListObject> list = new();
Assert.IsInstanceOf<Given>(list.FirstOrGiven<ListObject, Given>()); Assert.IsInstanceOf<Given>(list.FirstOrGiven<ListObject, Given>());
} }
[Test] [Test]
public void TestFirstOrGivenNoPredicate() public void TestFirstOrGivenNoPredicate()
{
List<ListObject> list = new()
{ {
List<ListObject> list = new() new ListObject {Index = 0},
{ new ListObject {Index = 1},
new ListObject {Index = 0}, new ListObject {Index = 2},
new ListObject {Index = 1}, new ListObject {Index = 3}
new ListObject {Index = 2}, };
new ListObject {Index = 3}
}; ListObject listObject = list.FirstOrGiven<ListObject, Given>();
ListObject listObject = list.FirstOrGiven<ListObject, Given>();
Assert.IsNotInstanceOf<Given>(listObject); Assert.IsNotInstanceOf<Given>(listObject);
Assert.AreEqual(0, listObject.Index); Assert.AreEqual(0, listObject.Index);
} }
[Test] [Test]
[SuppressMessage("ReSharper", "CollectionNeverUpdated.Local")] [SuppressMessage("ReSharper", "CollectionNeverUpdated.Local")]
public void TestFirstOrGivenPredicateEmpty() public void TestFirstOrGivenPredicateEmpty()
{ {
List<ListObject> list = new(); List<ListObject> list = new();
Assert.IsInstanceOf<Given>(list.FirstOrGiven<ListObject, Given>(o => o.Index == 2)); Assert.IsInstanceOf<Given>(list.FirstOrGiven<ListObject, Given>(o => o.Index == 2));
} }
[Test] [Test]
public void TestFirstOrGivenPredicate() public void TestFirstOrGivenPredicate()
{ {
List<ListObject> list = new() List<ListObject> list = new()
{
new ListObject {Index = 0},
new ListObject {Index = 1},
new ListObject {Index = 2},
new ListObject {Index = 3}
};
ListObject listObject = list.FirstOrGiven<ListObject, Given>(o => o.Index == 2);
Assert.IsNotInstanceOf<Given>(listObject);
Assert.AreEqual(2, listObject.Index);
}
[Test]
public void TestForEach()
{ {
Mock<ITest> test1 = new(); new ListObject {Index = 0},
Mock<ITest> test2 = new(); new ListObject {Index = 1},
Mock<ITest> test3 = new(); new ListObject {Index = 2},
Mock<ITest> test4 = new(); new ListObject {Index = 3}
};
ListObject listObject = list.FirstOrGiven<ListObject, Given>(o => o.Index == 2);
Assert.IsNotInstanceOf<Given>(listObject);
Assert.AreEqual(2, listObject.Index);
}
[Test]
public void TestForEach()
{
Mock<ITest> test1 = new();
Mock<ITest> test2 = new();
Mock<ITest> test3 = new();
Mock<ITest> test4 = new();
IEnumerable<ITest> enumerable = new[] { test1.Object, test2.Object, test3.Object, test4.Object }; IEnumerable<ITest> enumerable = new[] { test1.Object, test2.Object, test3.Object, test4.Object };
enumerable.ForEach(t => t.DoSomething()); enumerable.ForEach(t => t.DoSomething());
test1.Verify(t => t.DoSomething(), Times.Once); test1.Verify(t => t.DoSomething(), Times.Once);
test2.Verify(t => t.DoSomething(), Times.Once); test2.Verify(t => t.DoSomething(), Times.Once);
test3.Verify(t => t.DoSomething(), Times.Once); test3.Verify(t => t.DoSomething(), Times.Once);
test4.Verify(t => t.DoSomething(), Times.Once); test4.Verify(t => t.DoSomething(), Times.Once);
}
} }
} }

@ -7,267 +7,266 @@ using LightweightIocContainer;
using LightweightIocContainer.Exceptions; using LightweightIocContainer.Exceptions;
using NUnit.Framework; using NUnit.Framework;
namespace Test.LightweightIocContainer namespace Test.LightweightIocContainer;
[TestFixture]
public class FluentFactoryRegistrationTest
{ {
[TestFixture] public interface ITest
public class FluentFactoryRegistrationTest
{ {
public interface ITest
{
} }
private class Test : ITest private class Test : ITest
{ {
} }
private class TestByte : ITest private class TestByte : ITest
{ {
[UsedImplicitly] [UsedImplicitly]
private readonly byte _id; private readonly byte _id;
public TestByte(byte id) => _id = id; public TestByte(byte id) => _id = id;
} }
[UsedImplicitly] [UsedImplicitly]
private class TestConstructor : ITest private class TestConstructor : ITest
{
public TestConstructor(string name, Test test)
{ {
public TestConstructor(string name, Test test)
{
} }
public TestConstructor(Test test, string name = null) public TestConstructor(Test test, string name = null)
{ {
}
} }
}
private interface ITestFactoryNoCreate private interface ITestFactoryNoCreate
{ {
} }
private interface ITestFactoryNonGenericClear private interface ITestFactoryNonGenericClear
{ {
ITest Create(); ITest Create();
void ClearMultitonInstance(); void ClearMultitonInstance();
} }
[UsedImplicitly] [UsedImplicitly]
public interface ITestFactory public interface ITestFactory
{ {
ITest Create(); ITest Create();
ITest Create(string name); ITest Create(string name);
ITest CreateTest(string name = null); ITest CreateTest(string name = null);
ITest Create(byte id); ITest Create(byte id);
} }
private class TestFactory : ITestFactory private class TestFactory : ITestFactory
{ {
public ITest Create() => new Test(); public ITest Create() => new Test();
public ITest Create(string name) => throw new System.NotImplementedException(); public ITest Create(string name) => throw new System.NotImplementedException();
public ITest CreateTest(string name = null) => throw new System.NotImplementedException(); public ITest CreateTest(string name = null) => throw new System.NotImplementedException();
public ITest Create(byte id) => throw new System.NotImplementedException(); public ITest Create(byte id) => throw new System.NotImplementedException();
} }
[UsedImplicitly] [UsedImplicitly]
public interface IMultitonTestFactory public interface IMultitonTestFactory
{ {
ITest Create(MultitonScope scope); ITest Create(MultitonScope scope);
void ClearMultitonInstance<T>(); void ClearMultitonInstance<T>();
} }
[UsedImplicitly] [UsedImplicitly]
public interface IInvalidMultitonTestFactory public interface IInvalidMultitonTestFactory
{ {
ITest Create(MultitonScope scope); ITest Create(MultitonScope scope);
ITest Create(int number); ITest Create(int number);
} }
[UsedImplicitly] [UsedImplicitly]
public interface ITestFactoryWrongReturn public interface ITestFactoryWrongReturn
{ {
public MultitonScope Create(); public MultitonScope Create();
} }
public class MultitonScope public class MultitonScope
{ {
} }
private IocContainer _iocContainer; private IocContainer _iocContainer;
[SetUp] [SetUp]
public void SetUp() => _iocContainer = new IocContainer(); public void SetUp() => _iocContainer = new IocContainer();
[TearDown] [TearDown]
public void TearDown() => _iocContainer.Dispose(); public void TearDown() => _iocContainer.Dispose();
[Test] [Test]
public void TestFluentFactoryRegistration() public void TestFluentFactoryRegistration()
{ {
_iocContainer.Register(r => r.Add<ITest, Test>().WithFactory<ITestFactory>()); _iocContainer.Register(r => r.Add<ITest, Test>().WithFactory<ITestFactory>());
ITestFactory factory = _iocContainer.Resolve<ITestFactory>(); ITestFactory factory = _iocContainer.Resolve<ITestFactory>();
ITest test = factory.Create(); ITest test = factory.Create();
ITest test2 = factory.CreateTest(); ITest test2 = factory.CreateTest();
Assert.IsInstanceOf<ITestFactory>(factory); Assert.IsInstanceOf<ITestFactory>(factory);
Assert.IsInstanceOf<ITest>(test); Assert.IsInstanceOf<ITest>(test);
Assert.IsInstanceOf<ITest>(test2); Assert.IsInstanceOf<ITest>(test2);
} }
[Test] [Test]
public void TestFluentFactoryRegistrationResolveWithoutFactoryFails() public void TestFluentFactoryRegistrationResolveWithoutFactoryFails()
{ {
_iocContainer.Register(r => r.Add<ITest, Test>().WithFactory<ITestFactory>()); _iocContainer.Register(r => r.Add<ITest, Test>().WithFactory<ITestFactory>());
Assert.Throws<DirectResolveWithRegisteredFactoryNotAllowed>(()=>_iocContainer.Resolve<ITest>()); Assert.Throws<DirectResolveWithRegisteredFactoryNotAllowed>(()=>_iocContainer.Resolve<ITest>());
} }
[Test] [Test]
public void TestFluentFactoryRegistration_CustomFactory() public void TestFluentFactoryRegistration_CustomFactory()
{ {
_iocContainer.Register(r => r.Add<ITest, Test>().WithFactory<ITestFactory, TestFactory>()); _iocContainer.Register(r => r.Add<ITest, Test>().WithFactory<ITestFactory, TestFactory>());
ITestFactory factory = _iocContainer.Resolve<ITestFactory>(); ITestFactory factory = _iocContainer.Resolve<ITestFactory>();
ITest test = factory.Create(); ITest test = factory.Create();
Assert.IsInstanceOf<ITestFactory>(factory); Assert.IsInstanceOf<ITestFactory>(factory);
Assert.IsInstanceOf<ITest>(test); Assert.IsInstanceOf<ITest>(test);
} }
[Test] [Test]
public void TestFluentFactoryRegistration_WithoutFactoryFails() public void TestFluentFactoryRegistration_WithoutFactoryFails()
{ {
_iocContainer.Register(r => r.Add<ITest, Test>().WithFactory<ITestFactory, TestFactory>()); _iocContainer.Register(r => r.Add<ITest, Test>().WithFactory<ITestFactory, TestFactory>());
Assert.Throws<DirectResolveWithRegisteredFactoryNotAllowed>(()=>_iocContainer.Resolve<ITest>()); Assert.Throws<DirectResolveWithRegisteredFactoryNotAllowed>(()=>_iocContainer.Resolve<ITest>());
} }
[Test] [Test]
public void TestRegisterFactoryWithoutCreate() => Assert.Throws<InvalidFactoryRegistrationException>(() => _iocContainer.Register(r => r.Add<ITest, Test>().WithFactory<ITestFactoryNoCreate>())); public void TestRegisterFactoryWithoutCreate() => Assert.Throws<InvalidFactoryRegistrationException>(() => _iocContainer.Register(r => r.Add<ITest, Test>().WithFactory<ITestFactoryNoCreate>()));
[Test] [Test]
public void TestRegisterFactoryClearMultitonsNonGeneric() => Assert.Throws<IllegalAbstractMethodCreationException>(() => _iocContainer.Register(r => r.Add<ITest, Test>().WithFactory<ITestFactoryNonGenericClear>())); public void TestRegisterFactoryClearMultitonsNonGeneric() => Assert.Throws<IllegalAbstractMethodCreationException>(() => _iocContainer.Register(r => r.Add<ITest, Test>().WithFactory<ITestFactoryNonGenericClear>()));
[Test] [Test]
public void TestResolveFromFactory() public void TestResolveFromFactory()
{ {
_iocContainer.Register(r => r.Add<ITest, Test>().WithFactory<ITestFactory>()); _iocContainer.Register(r => r.Add<ITest, Test>().WithFactory<ITestFactory>());
ITestFactory testFactory = _iocContainer.Resolve<ITestFactory>(); ITestFactory testFactory = _iocContainer.Resolve<ITestFactory>();
ITest createdTest = testFactory.Create(); ITest createdTest = testFactory.Create();
Assert.IsInstanceOf<Test>(createdTest); Assert.IsInstanceOf<Test>(createdTest);
} }
[Test] [Test]
public void TestResolveFromFactoryWithParams() public void TestResolveFromFactoryWithParams()
{ {
_iocContainer.Register(r => r.Add<ITest, TestConstructor>().WithFactory<ITestFactory>()); _iocContainer.Register(r => r.Add<ITest, TestConstructor>().WithFactory<ITestFactory>());
_iocContainer.Register(r => r.Add<Test, Test>()); //this registration is abnormal and should only be used in unit tests _iocContainer.Register(r => r.Add<Test, Test>()); //this registration is abnormal and should only be used in unit tests
ITestFactory testFactory = _iocContainer.Resolve<ITestFactory>(); ITestFactory testFactory = _iocContainer.Resolve<ITestFactory>();
ITest createdTest = testFactory.Create("Test"); ITest createdTest = testFactory.Create("Test");
Assert.IsInstanceOf<TestConstructor>(createdTest); Assert.IsInstanceOf<TestConstructor>(createdTest);
} }
[Test] [Test]
public void TestResolveFromFactoryWithDefaultParamCreate() public void TestResolveFromFactoryWithDefaultParamCreate()
{ {
_iocContainer.Register(r => r.Add<ITest, TestConstructor>().WithFactory<ITestFactory>()); _iocContainer.Register(r => r.Add<ITest, TestConstructor>().WithFactory<ITestFactory>());
_iocContainer.Register(r => r.Add<Test, Test>()); //this registration is abnormal and should only be used in unit tests _iocContainer.Register(r => r.Add<Test, Test>()); //this registration is abnormal and should only be used in unit tests
ITestFactory testFactory = _iocContainer.Resolve<ITestFactory>(); ITestFactory testFactory = _iocContainer.Resolve<ITestFactory>();
ITest createdTest = testFactory.CreateTest(); ITest createdTest = testFactory.CreateTest();
Assert.IsInstanceOf<TestConstructor>(createdTest); Assert.IsInstanceOf<TestConstructor>(createdTest);
} }
[Test] [Test]
public void TestResolveFromFactoryWithDefaultParamCtor() public void TestResolveFromFactoryWithDefaultParamCtor()
{ {
_iocContainer.Register(r => r.Add<ITest, TestConstructor>().WithFactory<ITestFactory>()); _iocContainer.Register(r => r.Add<ITest, TestConstructor>().WithFactory<ITestFactory>());
_iocContainer.Register(r => r.Add<Test, Test>()); //this registration is abnormal and should only be used in unit tests _iocContainer.Register(r => r.Add<Test, Test>()); //this registration is abnormal and should only be used in unit tests
ITestFactory testFactory = _iocContainer.Resolve<ITestFactory>(); ITestFactory testFactory = _iocContainer.Resolve<ITestFactory>();
ITest createdTest = testFactory.Create(); ITest createdTest = testFactory.Create();
Assert.IsInstanceOf<TestConstructor>(createdTest); Assert.IsInstanceOf<TestConstructor>(createdTest);
} }
[Test] [Test]
public void TestResolveFromFactoryWithByte() public void TestResolveFromFactoryWithByte()
{ {
_iocContainer.Register(r => r.Add<ITest, TestByte>().WithFactory<ITestFactory>()); _iocContainer.Register(r => r.Add<ITest, TestByte>().WithFactory<ITestFactory>());
ITestFactory testFactory = _iocContainer.Resolve<ITestFactory>(); ITestFactory testFactory = _iocContainer.Resolve<ITestFactory>();
ITest createdTest = testFactory.Create(1); ITest createdTest = testFactory.Create(1);
Assert.IsInstanceOf<TestByte>(createdTest); Assert.IsInstanceOf<TestByte>(createdTest);
} }
[Test] [Test]
public void TestResolveMultitonFromFactory() public void TestResolveMultitonFromFactory()
{ {
_iocContainer.Register(r => r.AddMultiton<ITest, Test, MultitonScope>().WithFactory<IMultitonTestFactory>()); _iocContainer.Register(r => r.AddMultiton<ITest, Test, MultitonScope>().WithFactory<IMultitonTestFactory>());
MultitonScope scope1 = new(); MultitonScope scope1 = new();
MultitonScope scope2 = new(); MultitonScope scope2 = new();
IMultitonTestFactory testFactory = _iocContainer.Resolve<IMultitonTestFactory>(); IMultitonTestFactory testFactory = _iocContainer.Resolve<IMultitonTestFactory>();
ITest resolvedTest1 = testFactory.Create(scope1); ITest resolvedTest1 = testFactory.Create(scope1);
ITest resolvedTest2 = testFactory.Create(scope1); ITest resolvedTest2 = testFactory.Create(scope1);
ITest resolvedTest3 = testFactory.Create(scope2); ITest resolvedTest3 = testFactory.Create(scope2);
Assert.AreSame(resolvedTest1, resolvedTest2); Assert.AreSame(resolvedTest1, resolvedTest2);
Assert.AreNotSame(resolvedTest1, resolvedTest3); Assert.AreNotSame(resolvedTest1, resolvedTest3);
Assert.AreNotSame(resolvedTest2, resolvedTest3); Assert.AreNotSame(resolvedTest2, resolvedTest3);
} }
[Test] [Test]
public void TestResolveMultitonFromFactoryClearInstances() public void TestResolveMultitonFromFactoryClearInstances()
{ {
_iocContainer.Register(r => r.AddMultiton<ITest, Test, MultitonScope>().WithFactory<IMultitonTestFactory>()); _iocContainer.Register(r => r.AddMultiton<ITest, Test, MultitonScope>().WithFactory<IMultitonTestFactory>());
MultitonScope scope1 = new(); MultitonScope scope1 = new();
MultitonScope scope2 = new(); MultitonScope scope2 = new();
IMultitonTestFactory testFactory = _iocContainer.Resolve<IMultitonTestFactory>(); IMultitonTestFactory testFactory = _iocContainer.Resolve<IMultitonTestFactory>();
ITest resolvedTest1 = testFactory.Create(scope1); ITest resolvedTest1 = testFactory.Create(scope1);
ITest resolvedTest2 = testFactory.Create(scope1); ITest resolvedTest2 = testFactory.Create(scope1);
ITest resolvedTest3 = testFactory.Create(scope2); ITest resolvedTest3 = testFactory.Create(scope2);
Assert.AreSame(resolvedTest1, resolvedTest2); Assert.AreSame(resolvedTest1, resolvedTest2);
Assert.AreNotSame(resolvedTest1, resolvedTest3); Assert.AreNotSame(resolvedTest1, resolvedTest3);
Assert.AreNotSame(resolvedTest2, resolvedTest3); Assert.AreNotSame(resolvedTest2, resolvedTest3);
testFactory.ClearMultitonInstance<ITest>(); testFactory.ClearMultitonInstance<ITest>();
ITest resolvedTest4 = testFactory.Create(scope1); ITest resolvedTest4 = testFactory.Create(scope1);
ITest resolvedTest5 = testFactory.Create(scope2); ITest resolvedTest5 = testFactory.Create(scope2);
Assert.AreNotSame(resolvedTest1, resolvedTest4); Assert.AreNotSame(resolvedTest1, resolvedTest4);
Assert.AreNotSame(resolvedTest2, resolvedTest4); Assert.AreNotSame(resolvedTest2, resolvedTest4);
Assert.AreNotSame(resolvedTest3, resolvedTest5); Assert.AreNotSame(resolvedTest3, resolvedTest5);
} }
[Test] [Test]
public void InvalidMultitonFactoryRegistrationFactoryWithoutParameter() => public void InvalidMultitonFactoryRegistrationFactoryWithoutParameter() =>
Assert.Throws<InvalidFactoryRegistrationException>(() => _iocContainer.Register(r => r.AddMultiton<ITest, Test, MultitonScope>().WithFactory<ITestFactory>())); Assert.Throws<InvalidFactoryRegistrationException>(() => _iocContainer.Register(r => r.AddMultiton<ITest, Test, MultitonScope>().WithFactory<ITestFactory>()));
[Test] [Test]
public void InvalidMultitonFactoryRegistrationFactoryWithoutScopeAsFirstParameter() => public void InvalidMultitonFactoryRegistrationFactoryWithoutScopeAsFirstParameter() =>
Assert.Throws<InvalidFactoryRegistrationException>(() => _iocContainer.Register(r => r.AddMultiton<ITest, Test, MultitonScope>().WithFactory<IInvalidMultitonTestFactory>())); Assert.Throws<InvalidFactoryRegistrationException>(() => _iocContainer.Register(r => r.AddMultiton<ITest, Test, MultitonScope>().WithFactory<IInvalidMultitonTestFactory>()));
[Test] [Test]
public void TestInvalidCreateMethodReturnType() => public void TestInvalidCreateMethodReturnType() =>
Assert.Throws<InvalidFactoryRegistrationException>(() => _iocContainer.Register(r => r.Add<ITest, Test>().WithFactory<ITestFactoryWrongReturn>())); Assert.Throws<InvalidFactoryRegistrationException>(() => _iocContainer.Register(r => r.Add<ITest, Test>().WithFactory<ITestFactoryWrongReturn>()));
}
} }

@ -7,158 +7,157 @@ using JetBrains.Annotations;
using LightweightIocContainer; using LightweightIocContainer;
using NUnit.Framework; using NUnit.Framework;
namespace Test.LightweightIocContainer namespace Test.LightweightIocContainer;
[TestFixture]
public class IocContainerInterfaceSegregationTest
{ {
[TestFixture] private interface IBar
public class IocContainerInterfaceSegregationTest
{ {
private interface IBar
{
} }
private interface IFoo private interface IFoo
{ {
void ThrowFoo(); void ThrowFoo();
} }
private interface IAnotherBar private interface IAnotherBar
{ {
} }
private interface IAnotherFoo private interface IAnotherFoo
{ {
} }
private interface IAnotherOne private interface IAnotherOne
{ {
} }
[UsedImplicitly] [UsedImplicitly]
private class Foo : IFoo, IBar, IAnotherFoo, IAnotherBar, IAnotherOne private class Foo : IFoo, IBar, IAnotherFoo, IAnotherBar, IAnotherOne
{ {
public void ThrowFoo() => throw new Exception("Foo"); public void ThrowFoo() => throw new Exception("Foo");
} }
private IocContainer _container; private IocContainer _container;
[SetUp] [SetUp]
public void SetUp() => _container = new IocContainer(); public void SetUp() => _container = new IocContainer();
[TearDown] [TearDown]
public void TearDown() => _container.Dispose(); public void TearDown() => _container.Dispose();
[Test] [Test]
public void TestRegistrationOnCreate2() public void TestRegistrationOnCreate2()
{ {
_container.Register(r => r.Add<IBar, IFoo, Foo>().OnCreate(foo => foo.ThrowFoo())); _container.Register(r => r.Add<IBar, IFoo, Foo>().OnCreate(foo => foo.ThrowFoo()));
Exception fooException = Assert.Throws<Exception>(() => _container.Resolve<IFoo>()); Exception fooException = Assert.Throws<Exception>(() => _container.Resolve<IFoo>());
Assert.AreEqual("Foo", fooException?.Message); Assert.AreEqual("Foo", fooException?.Message);
Exception barException = Assert.Throws<Exception>(() => _container.Resolve<IBar>()); Exception barException = Assert.Throws<Exception>(() => _container.Resolve<IBar>());
Assert.AreEqual("Foo", barException?.Message); Assert.AreEqual("Foo", barException?.Message);
} }
[Test] [Test]
public void TestRegistrationOnCreate3() public void TestRegistrationOnCreate3()
{ {
_container.Register(r => r.Add<IBar, IFoo, IAnotherFoo, Foo>().OnCreate(foo => foo.ThrowFoo())); _container.Register(r => r.Add<IBar, IFoo, IAnotherFoo, Foo>().OnCreate(foo => foo.ThrowFoo()));
Exception fooException = Assert.Throws<Exception>(() => _container.Resolve<IFoo>()); Exception fooException = Assert.Throws<Exception>(() => _container.Resolve<IFoo>());
Assert.AreEqual("Foo", fooException?.Message); Assert.AreEqual("Foo", fooException?.Message);
Exception barException = Assert.Throws<Exception>(() => _container.Resolve<IBar>()); Exception barException = Assert.Throws<Exception>(() => _container.Resolve<IBar>());
Assert.AreEqual("Foo", barException?.Message); Assert.AreEqual("Foo", barException?.Message);
Exception anotherFooException = Assert.Throws<Exception>(() => _container.Resolve<IAnotherFoo>()); Exception anotherFooException = Assert.Throws<Exception>(() => _container.Resolve<IAnotherFoo>());
Assert.AreEqual("Foo", anotherFooException?.Message); Assert.AreEqual("Foo", anotherFooException?.Message);
} }
[Test] [Test]
public void TestRegistrationOnCreate4() public void TestRegistrationOnCreate4()
{ {
_container.Register(r => r.Add<IBar, IFoo, IAnotherFoo, IAnotherBar, Foo>().OnCreate(foo => foo.ThrowFoo())); _container.Register(r => r.Add<IBar, IFoo, IAnotherFoo, IAnotherBar, Foo>().OnCreate(foo => foo.ThrowFoo()));
Exception fooException = Assert.Throws<Exception>(() => _container.Resolve<IFoo>()); Exception fooException = Assert.Throws<Exception>(() => _container.Resolve<IFoo>());
Assert.AreEqual("Foo", fooException?.Message); Assert.AreEqual("Foo", fooException?.Message);
Exception barException = Assert.Throws<Exception>(() => _container.Resolve<IBar>()); Exception barException = Assert.Throws<Exception>(() => _container.Resolve<IBar>());
Assert.AreEqual("Foo", barException?.Message); Assert.AreEqual("Foo", barException?.Message);
Exception anotherFooException = Assert.Throws<Exception>(() => _container.Resolve<IAnotherFoo>()); Exception anotherFooException = Assert.Throws<Exception>(() => _container.Resolve<IAnotherFoo>());
Assert.AreEqual("Foo", anotherFooException?.Message); Assert.AreEqual("Foo", anotherFooException?.Message);
Exception anotherBarException = Assert.Throws<Exception>(() => _container.Resolve<IAnotherBar>()); Exception anotherBarException = Assert.Throws<Exception>(() => _container.Resolve<IAnotherBar>());
Assert.AreEqual("Foo", anotherBarException?.Message); Assert.AreEqual("Foo", anotherBarException?.Message);
} }
[Test] [Test]
public void TestRegistrationOnCreate5() public void TestRegistrationOnCreate5()
{ {
_container.Register(r => r.Add<IBar, IFoo, IAnotherFoo, IAnotherBar, IAnotherOne, Foo>().OnCreate(foo => foo.ThrowFoo())); _container.Register(r => r.Add<IBar, IFoo, IAnotherFoo, IAnotherBar, IAnotherOne, Foo>().OnCreate(foo => foo.ThrowFoo()));
Exception fooException = Assert.Throws<Exception>(() => _container.Resolve<IFoo>()); Exception fooException = Assert.Throws<Exception>(() => _container.Resolve<IFoo>());
Assert.AreEqual("Foo", fooException?.Message); Assert.AreEqual("Foo", fooException?.Message);
Exception barException = Assert.Throws<Exception>(() => _container.Resolve<IBar>()); Exception barException = Assert.Throws<Exception>(() => _container.Resolve<IBar>());
Assert.AreEqual("Foo", barException?.Message); Assert.AreEqual("Foo", barException?.Message);
Exception anotherFooException = Assert.Throws<Exception>(() => _container.Resolve<IAnotherFoo>()); Exception anotherFooException = Assert.Throws<Exception>(() => _container.Resolve<IAnotherFoo>());
Assert.AreEqual("Foo", anotherFooException?.Message); Assert.AreEqual("Foo", anotherFooException?.Message);
Exception anotherBarException = Assert.Throws<Exception>(() => _container.Resolve<IAnotherBar>()); Exception anotherBarException = Assert.Throws<Exception>(() => _container.Resolve<IAnotherBar>());
Assert.AreEqual("Foo", anotherBarException?.Message); Assert.AreEqual("Foo", anotherBarException?.Message);
Exception anotherOneException = Assert.Throws<Exception>(() => _container.Resolve<IAnotherOne>()); Exception anotherOneException = Assert.Throws<Exception>(() => _container.Resolve<IAnotherOne>());
Assert.AreEqual("Foo", anotherOneException?.Message); Assert.AreEqual("Foo", anotherOneException?.Message);
} }
[Test] [Test]
public void TestResolveTransient() public void TestResolveTransient()
{ {
_container.Register(r => r.Add<IBar, IFoo, IAnotherFoo, IAnotherBar, IAnotherOne, Foo>()); _container.Register(r => r.Add<IBar, IFoo, IAnotherFoo, IAnotherBar, IAnotherOne, Foo>());
IFoo foo = _container.Resolve<IFoo>(); IFoo foo = _container.Resolve<IFoo>();
IBar bar = _container.Resolve<IBar>(); IBar bar = _container.Resolve<IBar>();
IAnotherFoo anotherFoo = _container.Resolve<IAnotherFoo>(); IAnotherFoo anotherFoo = _container.Resolve<IAnotherFoo>();
IAnotherBar anotherBar = _container.Resolve<IAnotherBar>(); IAnotherBar anotherBar = _container.Resolve<IAnotherBar>();
IAnotherOne anotherOne = _container.Resolve<IAnotherOne>(); IAnotherOne anotherOne = _container.Resolve<IAnotherOne>();
Assert.IsInstanceOf<Foo>(foo); Assert.IsInstanceOf<Foo>(foo);
Assert.IsInstanceOf<Foo>(bar); Assert.IsInstanceOf<Foo>(bar);
Assert.IsInstanceOf<Foo>(anotherFoo); Assert.IsInstanceOf<Foo>(anotherFoo);
Assert.IsInstanceOf<Foo>(anotherBar); Assert.IsInstanceOf<Foo>(anotherBar);
Assert.IsInstanceOf<Foo>(anotherOne); Assert.IsInstanceOf<Foo>(anotherOne);
} }
[Test] [Test]
public void TestResolveSingleton() public void TestResolveSingleton()
{ {
_container.Register(r => r.Add<IBar, IFoo, IAnotherFoo, IAnotherBar, IAnotherOne, Foo>(Lifestyle.Singleton)); _container.Register(r => r.Add<IBar, IFoo, IAnotherFoo, IAnotherBar, IAnotherOne, Foo>(Lifestyle.Singleton));
IFoo foo = _container.Resolve<IFoo>(); IFoo foo = _container.Resolve<IFoo>();
IBar bar = _container.Resolve<IBar>(); IBar bar = _container.Resolve<IBar>();
IAnotherFoo anotherFoo = _container.Resolve<IAnotherFoo>(); IAnotherFoo anotherFoo = _container.Resolve<IAnotherFoo>();
IAnotherBar anotherBar = _container.Resolve<IAnotherBar>(); IAnotherBar anotherBar = _container.Resolve<IAnotherBar>();
IAnotherOne anotherOne = _container.Resolve<IAnotherOne>(); IAnotherOne anotherOne = _container.Resolve<IAnotherOne>();
Assert.IsInstanceOf<Foo>(foo); Assert.IsInstanceOf<Foo>(foo);
Assert.IsInstanceOf<Foo>(bar); Assert.IsInstanceOf<Foo>(bar);
Assert.IsInstanceOf<Foo>(anotherFoo); Assert.IsInstanceOf<Foo>(anotherFoo);
Assert.IsInstanceOf<Foo>(anotherBar); Assert.IsInstanceOf<Foo>(anotherBar);
Assert.IsInstanceOf<Foo>(anotherOne); Assert.IsInstanceOf<Foo>(anotherOne);
Assert.AreEqual(foo, bar); Assert.AreEqual(foo, bar);
Assert.AreEqual(foo, anotherFoo); Assert.AreEqual(foo, anotherFoo);
Assert.AreEqual(foo, anotherBar); Assert.AreEqual(foo, anotherBar);
Assert.AreEqual(foo, anotherOne); Assert.AreEqual(foo, anotherOne);
Assert.AreSame(foo, bar); Assert.AreSame(foo, bar);
Assert.AreSame(foo, anotherFoo); Assert.AreSame(foo, anotherFoo);
Assert.AreSame(foo, anotherBar); Assert.AreSame(foo, anotherBar);
Assert.AreSame(foo, anotherOne); Assert.AreSame(foo, anotherOne);
}
} }
} }

@ -6,154 +6,153 @@ using JetBrains.Annotations;
using LightweightIocContainer; using LightweightIocContainer;
using NUnit.Framework; using NUnit.Framework;
namespace Test.LightweightIocContainer namespace Test.LightweightIocContainer;
[TestFixture]
// ReSharper disable MemberHidesStaticFromOuterClass
public class IocContainerParameterRegistrationTest
{ {
[TestFixture] [UsedImplicitly]
// ReSharper disable MemberHidesStaticFromOuterClass public interface IA
public class IocContainerParameterRegistrationTest
{ {
[UsedImplicitly] IB B { get; }
public interface IA IC C { get; }
{ }
IB B { get; }
IC C { get; }
}
[UsedImplicitly] [UsedImplicitly]
public interface IB public interface IB
{ {
} }
[UsedImplicitly] [UsedImplicitly]
public interface IC public interface IC
{ {
} }
[UsedImplicitly] [UsedImplicitly]
public interface ID public interface ID
{ {
IA A { get; } IA A { get; }
IA A2 { get; } IA A2 { get; }
IB B { get; } IB B { get; }
IC C { get; } IC C { get; }
} }
[UsedImplicitly] [UsedImplicitly]
private class A : IA private class A : IA
{
public A(IB b, IC c)
{ {
public A(IB b, IC c) B = b;
{ C = c;
B = b;
C = c;
}
public IB B { get; }
public IC C { get; }
} }
[UsedImplicitly] public IB B { get; }
private class B : IB public IC C { get; }
}
[UsedImplicitly]
private class B : IB
{
public B(IC c)
{ {
public B(IC c)
{
}
} }
}
[UsedImplicitly] [UsedImplicitly]
private class C : IC private class C : IC
{ {
} }
[UsedImplicitly] [UsedImplicitly]
private class D : ID private class D : ID
{
public D(IA a, IA a2, IB b, IC c)
{ {
public D(IA a, IA a2, IB b, IC c) A = a;
{ A2 = a2;
A = a; B = b;
A2 = a2; C = c;
B = b;
C = c;
}
public IA A { get; }
public IA A2 { get; }
public IB B { get; }
public IC C { get; }
} }
public IA A { get; }
public IA A2 { get; }
public IB B { get; }
public IC C { get; }
}
private IocContainer _iocContainer; private IocContainer _iocContainer;
[SetUp] [SetUp]
public void SetUp() => _iocContainer = new IocContainer(); public void SetUp() => _iocContainer = new IocContainer();
[TearDown] [TearDown]
public void TearDown() => _iocContainer.Dispose(); public void TearDown() => _iocContainer.Dispose();
[Test] [Test]
public void TestResolveOnlyRegistrationParameters() public void TestResolveOnlyRegistrationParameters()
{ {
IC c = new C(); IC c = new C();
IB b = new B(c); IB b = new B(c);
_iocContainer.Register(r => r.Add<IA, A>().WithParameters(b, c)); _iocContainer.Register(r => r.Add<IA, A>().WithParameters(b, c));
IA a = _iocContainer.Resolve<IA>(); IA a = _iocContainer.Resolve<IA>();
Assert.AreEqual(b, a.B); Assert.AreEqual(b, a.B);
Assert.AreEqual(c, a.C); Assert.AreEqual(c, a.C);
} }
[Test] [Test]
public void TestResolveRegistrationAndResolveParameters() public void TestResolveRegistrationAndResolveParameters()
{ {
IC c = new C(); IC c = new C();
IB b = new B(c); IB b = new B(c);
_iocContainer.Register(r => r.Add<IA, A>().WithParameters(b)); _iocContainer.Register(r => r.Add<IA, A>().WithParameters(b));
IA a = _iocContainer.Resolve<IA>(c); IA a = _iocContainer.Resolve<IA>(c);
Assert.AreEqual(b, a.B); Assert.AreEqual(b, a.B);
Assert.AreEqual(c, a.C); Assert.AreEqual(c, a.C);
} }
[Test] [Test]
public void TestResolveRegistrationAndResolveParametersMixedOrder() public void TestResolveRegistrationAndResolveParametersMixedOrder()
{ {
IC c = new C(); IC c = new C();
IB b = new B(c); IB b = new B(c);
IA a = new A(b, c); IA a = new A(b, c);
IA a2 = new A(b, c); IA a2 = new A(b, c);
_iocContainer.Register(r => r.Add<ID, D>().WithParameters((0, a), (2, b), (3, c))); _iocContainer.Register(r => r.Add<ID, D>().WithParameters((0, a), (2, b), (3, c)));
ID d = _iocContainer.Resolve<ID>(a2); ID d = _iocContainer.Resolve<ID>(a2);
Assert.AreEqual(a, d.A); Assert.AreEqual(a, d.A);
Assert.AreEqual(a2, d.A2); Assert.AreEqual(a2, d.A2);
Assert.AreEqual(b, d.B); Assert.AreEqual(b, d.B);
Assert.AreEqual(c, d.C); Assert.AreEqual(c, d.C);
} }
[Test] [Test]
public void TestResolveRegistrationParametersAndResolvedParameters() public void TestResolveRegistrationParametersAndResolvedParameters()
{ {
IC c = new C(); IC c = new C();
IB b = new B(c); IB b = new B(c);
IA a = new A(b, c); IA a = new A(b, c);
IA a2 = new A(b, c); IA a2 = new A(b, c);
_iocContainer.Register(r => r.Add<ID, D>().WithParameters(a2)); _iocContainer.Register(r => r.Add<ID, D>().WithParameters(a2));
_iocContainer.Register(r => r.Add<IB, B>()); _iocContainer.Register(r => r.Add<IB, B>());
_iocContainer.Register(r => r.Add<IC, C>()); _iocContainer.Register(r => r.Add<IC, C>());
ID d = _iocContainer.Resolve<ID>(a); ID d = _iocContainer.Resolve<ID>(a);
Assert.AreEqual(a, d.A2); Assert.AreEqual(a, d.A2);
Assert.AreEqual(a2, d.A); Assert.AreEqual(a2, d.A);
}
} }
} }

@ -9,158 +9,157 @@ using LightweightIocContainer.Exceptions;
using Moq; using Moq;
using NUnit.Framework; using NUnit.Framework;
namespace Test.LightweightIocContainer namespace Test.LightweightIocContainer;
[TestFixture]
public class IocContainerRecursionTest
{ {
[TestFixture] [UsedImplicitly]
public class IocContainerRecursionTest public interface IFoo
{ {
[UsedImplicitly]
public interface IFoo
{
} }
[UsedImplicitly] [UsedImplicitly]
public interface IBar public interface IBar
{ {
} }
[UsedImplicitly] [UsedImplicitly]
private class Foo : IFoo private class Foo : IFoo
{
public Foo(IBar bar)
{ {
public Foo(IBar bar)
{
}
} }
}
[UsedImplicitly] [UsedImplicitly]
private class Bar : IBar private class Bar : IBar
{
public Bar(IFoo foo)
{ {
public Bar(IFoo foo)
{
}
} }
}
[UsedImplicitly] [UsedImplicitly]
public interface IA public interface IA
{ {
} }
[UsedImplicitly] [UsedImplicitly]
public interface IB public interface IB
{ {
} }
[UsedImplicitly] [UsedImplicitly]
public interface IC public interface IC
{ {
} }
[UsedImplicitly] [UsedImplicitly]
private class A : IA private class A : IA
{
public A(IB b, IC c)
{ {
public A(IB b, IC c)
{
}
} }
}
[UsedImplicitly] [UsedImplicitly]
private class B : IB private class B : IB
{
public B(IC c)
{ {
public B(IC c)
{
}
} }
}
[UsedImplicitly] [UsedImplicitly]
private class C : IC private class C : IC
{ {
} }
[UsedImplicitly] [UsedImplicitly]
private class ATwoCtor : IA private class ATwoCtor : IA
{ {
public ATwoCtor(IB b) => Console.WriteLine("A with args"); public ATwoCtor(IB b) => Console.WriteLine("A with args");
public ATwoCtor() => Console.WriteLine("A without args"); public ATwoCtor() => Console.WriteLine("A without args");
} }
[UsedImplicitly] [UsedImplicitly]
private class BTwoCtor : IB private class BTwoCtor : IB
{ {
public BTwoCtor(IA a) => Console.WriteLine("B with args"); public BTwoCtor(IA a) => Console.WriteLine("B with args");
public BTwoCtor() => Console.WriteLine("B without args"); public BTwoCtor() => Console.WriteLine("B without args");
} }
private IocContainer _iocContainer; private IocContainer _iocContainer;
[SetUp] [SetUp]
public void SetUp() => _iocContainer = new IocContainer(); public void SetUp() => _iocContainer = new IocContainer();
[TearDown] [TearDown]
public void TearDown() => _iocContainer.Dispose(); public void TearDown() => _iocContainer.Dispose();
[Test] [Test]
public void TestCircularDependencies() public void TestCircularDependencies()
{ {
_iocContainer.Register(r => r.Add<IFoo, Foo>()); _iocContainer.Register(r => r.Add<IFoo, Foo>());
_iocContainer.Register(r => r.Add<IBar, Bar>()); _iocContainer.Register(r => r.Add<IBar, Bar>());
NoMatchingConstructorFoundException noMatchingConstructorFoundException = Assert.Throws<NoMatchingConstructorFoundException>(() => _iocContainer.Resolve<IFoo>()); NoMatchingConstructorFoundException noMatchingConstructorFoundException = Assert.Throws<NoMatchingConstructorFoundException>(() => _iocContainer.Resolve<IFoo>());
ConstructorNotMatchingException fooConstructorNotMatchingException = (ConstructorNotMatchingException) noMatchingConstructorFoundException?.InnerExceptions[0]; ConstructorNotMatchingException fooConstructorNotMatchingException = (ConstructorNotMatchingException) noMatchingConstructorFoundException?.InnerExceptions[0];
NoMatchingConstructorFoundException noMatchingBarConstructorFoundException = (NoMatchingConstructorFoundException) fooConstructorNotMatchingException?.InnerExceptions[0]; NoMatchingConstructorFoundException noMatchingBarConstructorFoundException = (NoMatchingConstructorFoundException) fooConstructorNotMatchingException?.InnerExceptions[0];
ConstructorNotMatchingException barConstructorNotMatchingException = (ConstructorNotMatchingException) noMatchingBarConstructorFoundException?.InnerExceptions[0]; ConstructorNotMatchingException barConstructorNotMatchingException = (ConstructorNotMatchingException) noMatchingBarConstructorFoundException?.InnerExceptions[0];
CircularDependencyException exception = (CircularDependencyException) barConstructorNotMatchingException?.InnerExceptions[0]; CircularDependencyException exception = (CircularDependencyException) barConstructorNotMatchingException?.InnerExceptions[0];
Assert.AreEqual(typeof(IFoo), exception?.ResolvingType); Assert.AreEqual(typeof(IFoo), exception?.ResolvingType);
Assert.AreEqual(2, exception.ResolveStack.Count); Assert.AreEqual(2, exception.ResolveStack.Count);
string message = $"Circular dependency has been detected when trying to resolve `{typeof(IFoo)}`.\n" + string message = $"Circular dependency has been detected when trying to resolve `{typeof(IFoo)}`.\n" +
"Resolve stack that resulted in the circular dependency:\n" + "Resolve stack that resulted in the circular dependency:\n" +
$"\t`{typeof(IFoo)}` resolved as dependency of\n" + $"\t`{typeof(IFoo)}` resolved as dependency of\n" +
$"\t`{typeof(IBar)}` resolved as dependency of\n" + $"\t`{typeof(IBar)}` resolved as dependency of\n" +
$"\t`{typeof(IFoo)}` which is the root type being resolved."; $"\t`{typeof(IFoo)}` which is the root type being resolved.";
Assert.AreEqual(message, exception.Message); Assert.AreEqual(message, exception.Message);
} }
[Test] [Test]
public void TestNonCircularDependencies() public void TestNonCircularDependencies()
{ {
_iocContainer.Register(r => r.Add<IA, A>()); _iocContainer.Register(r => r.Add<IA, A>());
_iocContainer.Register(r => r.Add<IB, B>()); _iocContainer.Register(r => r.Add<IB, B>());
_iocContainer.Register(r => r.Add<IC, C>()); _iocContainer.Register(r => r.Add<IC, C>());
IA a = _iocContainer.Resolve<IA>(); IA a = _iocContainer.Resolve<IA>();
Assert.IsNotNull(a); Assert.IsNotNull(a);
} }
[Test] [Test]
public void TestRecursionWithParam() public void TestRecursionWithParam()
{ {
_iocContainer.Register(r => r.Add<IFoo, Foo>()); _iocContainer.Register(r => r.Add<IFoo, Foo>());
_iocContainer.Register(r => r.Add<IBar, Bar>()); _iocContainer.Register(r => r.Add<IBar, Bar>());
Assert.DoesNotThrow(() => _iocContainer.Resolve<IFoo>(new Mock<IBar>().Object)); Assert.DoesNotThrow(() => _iocContainer.Resolve<IFoo>(new Mock<IBar>().Object));
Assert.DoesNotThrow(() => _iocContainer.Resolve<IBar>(new Mock<IFoo>().Object)); Assert.DoesNotThrow(() => _iocContainer.Resolve<IBar>(new Mock<IFoo>().Object));
} }
[Test] [Test]
public void TestNonCircularCrossDependencies() public void TestNonCircularCrossDependencies()
{ {
_iocContainer.Register(r => r.Add<IA, ATwoCtor>()); _iocContainer.Register(r => r.Add<IA, ATwoCtor>());
_iocContainer.Register(r => r.Add<IB, BTwoCtor>()); _iocContainer.Register(r => r.Add<IB, BTwoCtor>());
Assert.DoesNotThrow(() => _iocContainer.Resolve<IA>()); Assert.DoesNotThrow(() => _iocContainer.Resolve<IA>());
Assert.DoesNotThrow(() => _iocContainer.Resolve<IB>()); Assert.DoesNotThrow(() => _iocContainer.Resolve<IB>());
}
} }
} }

@ -7,356 +7,355 @@ using LightweightIocContainer.Interfaces.Registrations;
using Moq; using Moq;
using NUnit.Framework; using NUnit.Framework;
namespace Test.LightweightIocContainer namespace Test.LightweightIocContainer;
[TestFixture]
public class IocContainerTest
{ {
[TestFixture] private interface ITest
public class IocContainerTest
{ {
private interface ITest
{
} }
private interface IFoo private interface IFoo
{ {
} }
private class Test : ITest private class Test : ITest
{ {
} }
[UsedImplicitly] [UsedImplicitly]
private class TestConstructor : ITest private class TestConstructor : ITest
{
public TestConstructor(string name, Test test)
{ {
public TestConstructor(string name, Test test)
{
}
public TestConstructor(Test test, string name = null)
{
}
public TestConstructor(IFoo foo, string name)
{
}
} }
[UsedImplicitly] public TestConstructor(Test test, string name = null)
private class TestPrivateConstructor : ITest
{ {
private TestPrivateConstructor()
{
}
} }
[UsedImplicitly] public TestConstructor(IFoo foo, string name)
private class TestMultipleConstructors : ITest
{ {
public TestMultipleConstructors(string name, bool success)
{
} }
}
public TestMultipleConstructors(string name) [UsedImplicitly]
{ private class TestPrivateConstructor : ITest
{
private TestPrivateConstructor()
{
}
} }
}
[UsedImplicitly] [UsedImplicitly]
private class TestWithFoo : ITest private class TestMultipleConstructors : ITest
{
public TestMultipleConstructors(string name, bool success)
{ {
public TestWithFoo(IFoo testFoo) => TestFoo = testFoo;
public IFoo TestFoo { get; }
} }
[UsedImplicitly] public TestMultipleConstructors(string name)
private class Foo : IFoo
{ {
} }
}
[UsedImplicitly] [UsedImplicitly]
private class FooConstructor : IFoo private class TestWithFoo : ITest
{
public TestWithFoo(IFoo testFoo) => TestFoo = testFoo;
public IFoo TestFoo { get; }
}
[UsedImplicitly]
private class Foo : IFoo
{
}
[UsedImplicitly]
private class FooConstructor : IFoo
{
public FooConstructor(string test)
{ {
public FooConstructor(string test)
{
}
} }
}
private class MultitonScope private class MultitonScope
{ {
} }
private IocContainer _iocContainer; private IocContainer _iocContainer;
[SetUp] [SetUp]
public void SetUp() => _iocContainer = new IocContainer(); public void SetUp() => _iocContainer = new IocContainer();
[TearDown] [TearDown]
public void TearDown() => _iocContainer.Dispose(); public void TearDown() => _iocContainer.Dispose();
[Test] [Test]
public void TestInstall() public void TestInstall()
{ {
Mock<IIocInstaller> installerMock = new(); Mock<IIocInstaller> installerMock = new();
IIocContainer returnedContainer = _iocContainer.Install(installerMock.Object); IIocContainer returnedContainer = _iocContainer.Install(installerMock.Object);
installerMock.Verify(m => m.Install(It.IsAny<IRegistrationCollector>()), Times.Once); installerMock.Verify(m => m.Install(It.IsAny<IRegistrationCollector>()), Times.Once);
Assert.AreEqual(_iocContainer, returnedContainer); Assert.AreEqual(_iocContainer, returnedContainer);
} }
[Test] [Test]
public void TestInstallMultiple() public void TestInstallMultiple()
{ {
Mock<IIocInstaller> installer1Mock = new(); Mock<IIocInstaller> installer1Mock = new();
Mock<IIocInstaller> installer2Mock = new(); Mock<IIocInstaller> installer2Mock = new();
Mock<IIocInstaller> installer3Mock = new(); Mock<IIocInstaller> installer3Mock = new();
IIocContainer returnedContainer = _iocContainer.Install(installer1Mock.Object, installer2Mock.Object, installer3Mock.Object); IIocContainer returnedContainer = _iocContainer.Install(installer1Mock.Object, installer2Mock.Object, installer3Mock.Object);
installer1Mock.Verify(m => m.Install(It.IsAny<IRegistrationCollector>()), Times.Once); installer1Mock.Verify(m => m.Install(It.IsAny<IRegistrationCollector>()), Times.Once);
installer2Mock.Verify(m => m.Install(It.IsAny<IRegistrationCollector>()), Times.Once); installer2Mock.Verify(m => m.Install(It.IsAny<IRegistrationCollector>()), Times.Once);
installer3Mock.Verify(m => m.Install(It.IsAny<IRegistrationCollector>()), Times.Once); installer3Mock.Verify(m => m.Install(It.IsAny<IRegistrationCollector>()), Times.Once);
Assert.AreEqual(_iocContainer, returnedContainer); Assert.AreEqual(_iocContainer, returnedContainer);
} }
[Test] [Test]
public void TestRegister() => Assert.DoesNotThrow(() => _iocContainer.Register(r => r.Add<ITest, Test>())); public void TestRegister() => Assert.DoesNotThrow(() => _iocContainer.Register(r => r.Add<ITest, Test>()));
[Test] [Test]
public void TestRegisterTypeWithoutInterface() => Assert.DoesNotThrow(() => _iocContainer.Register(r => r.Add<Test>())); public void TestRegisterTypeWithoutInterface() => Assert.DoesNotThrow(() => _iocContainer.Register(r => r.Add<Test>()));
[Test] [Test]
public void TestRegisterMultiton() => Assert.DoesNotThrow(() => _iocContainer.Register(r => r.AddMultiton<ITest, Test, MultitonScope>())); public void TestRegisterMultiton() => Assert.DoesNotThrow(() => _iocContainer.Register(r => r.AddMultiton<ITest, Test, MultitonScope>()));
[Test] [Test]
public void TestInvalidMultitonRegistration() => Assert.Throws<InvalidRegistrationException>(() => _iocContainer.Register(r => r.Add<ITest, Test>(Lifestyle.Multiton))); public void TestInvalidMultitonRegistration() => Assert.Throws<InvalidRegistrationException>(() => _iocContainer.Register(r => r.Add<ITest, Test>(Lifestyle.Multiton)));
[Test] [Test]
public void TestRegisterMultipleDifferent() public void TestRegisterMultipleDifferent()
{ {
_iocContainer.Register(r => r.Add<ITest, Test>()); _iocContainer.Register(r => r.Add<ITest, Test>());
MultipleRegistrationException exception = Assert.Throws<MultipleRegistrationException>(() => _iocContainer.Register(r => r.Add<ITest, TestConstructor>())); MultipleRegistrationException exception = Assert.Throws<MultipleRegistrationException>(() => _iocContainer.Register(r => r.Add<ITest, TestConstructor>()));
Assert.AreEqual(typeof(ITest), exception?.Type); Assert.AreEqual(typeof(ITest), exception?.Type);
} }
[Test] [Test]
public void TestRegisterMultipleSame() public void TestRegisterMultipleSame()
{ {
_iocContainer.Register(r => r.Add<ITest, Test>()); _iocContainer.Register(r => r.Add<ITest, Test>());
Assert.DoesNotThrow(() => _iocContainer.Register(r => r.Add<ITest, Test>())); Assert.DoesNotThrow(() => _iocContainer.Register(r => r.Add<ITest, Test>()));
} }
[Test] [Test]
public void TestRegisterMultipleSameWithParameters() public void TestRegisterMultipleSameWithParameters()
{ {
_iocContainer.Register(r => r.Add<ITest, Test>().WithParameters("test", 1, new Foo())); _iocContainer.Register(r => r.Add<ITest, Test>().WithParameters("test", 1, new Foo()));
Assert.DoesNotThrow(() => _iocContainer.Register(r => r.Add<ITest, Test>().WithParameters("test", 1, new Foo()))); Assert.DoesNotThrow(() => _iocContainer.Register(r => r.Add<ITest, Test>().WithParameters("test", 1, new Foo())));
} }
[Test] [Test]
public void TestResolveNotRegistered() public void TestResolveNotRegistered()
{ {
TypeNotRegisteredException exception = Assert.Throws<TypeNotRegisteredException>(() => _iocContainer.Resolve<ITest>()); TypeNotRegisteredException exception = Assert.Throws<TypeNotRegisteredException>(() => _iocContainer.Resolve<ITest>());
Assert.AreEqual(typeof(ITest), exception?.Type); Assert.AreEqual(typeof(ITest), exception?.Type);
} }
[Test] [Test]
public void TestResolve() public void TestResolve()
{ {
_iocContainer.Register(r => r.Add<ITest, Test>()); _iocContainer.Register(r => r.Add<ITest, Test>());
ITest resolvedTest = _iocContainer.Resolve<ITest>(); ITest resolvedTest = _iocContainer.Resolve<ITest>();
Assert.IsInstanceOf<Test>(resolvedTest); Assert.IsInstanceOf<Test>(resolvedTest);
} }
[Test] [Test]
public void TestResolveWithoutInterface() public void TestResolveWithoutInterface()
{ {
_iocContainer.Register(r => r.Add<Test>()); _iocContainer.Register(r => r.Add<Test>());
Test resolvedTest = _iocContainer.Resolve<Test>(); Test resolvedTest = _iocContainer.Resolve<Test>();
Assert.IsInstanceOf<Test>(resolvedTest); Assert.IsInstanceOf<Test>(resolvedTest);
} }
[Test] [Test]
public void TestResolveInterfaceWithoutImplementation() public void TestResolveInterfaceWithoutImplementation()
{ {
_iocContainer.Register(r => r.Add<ITest>()); _iocContainer.Register(r => r.Add<ITest>());
Assert.Throws<InvalidRegistrationException>(() => _iocContainer.Resolve<ITest>()); Assert.Throws<InvalidRegistrationException>(() => _iocContainer.Resolve<ITest>());
} }
[Test] [Test]
public void TestResolveImplementationRegisteredWithInterface() public void TestResolveImplementationRegisteredWithInterface()
{ {
_iocContainer.Register(r => r.Add<ITest, Test>()); _iocContainer.Register(r => r.Add<ITest, Test>());
Test resolvedTest = _iocContainer.Resolve<Test>(); Test resolvedTest = _iocContainer.Resolve<Test>();
Assert.IsInstanceOf<Test>(resolvedTest); Assert.IsInstanceOf<Test>(resolvedTest);
} }
[Test] [Test]
public void TestResolveWithParams() public void TestResolveWithParams()
{ {
_iocContainer.Register(r => r.Add<ITest, TestConstructor>()); _iocContainer.Register(r => r.Add<ITest, TestConstructor>());
ITest resolvedTest = _iocContainer.Resolve<ITest>("Test", new Test()); ITest resolvedTest = _iocContainer.Resolve<ITest>("Test", new Test());
Assert.IsInstanceOf<TestConstructor>(resolvedTest); Assert.IsInstanceOf<TestConstructor>(resolvedTest);
} }
[Test] [Test]
public void TestResolveWithMissingParam() public void TestResolveWithMissingParam()
{ {
_iocContainer.Register(r => r.Add<ITest, TestConstructor>()); _iocContainer.Register(r => r.Add<ITest, TestConstructor>());
_iocContainer.Register(r => r.Add<Test, Test>()); //this registration is abnormal and should only be used in unit tests _iocContainer.Register(r => r.Add<Test, Test>()); //this registration is abnormal and should only be used in unit tests
ITest resolvedTest = _iocContainer.Resolve<ITest>("Test"); ITest resolvedTest = _iocContainer.Resolve<ITest>("Test");
Assert.IsInstanceOf<TestConstructor>(resolvedTest); Assert.IsInstanceOf<TestConstructor>(resolvedTest);
} }
[Test] [Test]
public void TestResolveSingleton() public void TestResolveSingleton()
{ {
_iocContainer.Register(r => r.Add<ITest, Test>(Lifestyle.Singleton)); _iocContainer.Register(r => r.Add<ITest, Test>(Lifestyle.Singleton));
ITest resolvedTest = _iocContainer.Resolve<ITest>(); ITest resolvedTest = _iocContainer.Resolve<ITest>();
ITest secondResolvedTest = _iocContainer.Resolve<ITest>(); ITest secondResolvedTest = _iocContainer.Resolve<ITest>();
Assert.AreEqual(resolvedTest, secondResolvedTest); Assert.AreEqual(resolvedTest, secondResolvedTest);
} }
[Test] [Test]
public void TestResolveMultiton() public void TestResolveMultiton()
{ {
_iocContainer.Register(r => r.AddMultiton<ITest, Test, MultitonScope>()); _iocContainer.Register(r => r.AddMultiton<ITest, Test, MultitonScope>());
MultitonScope scope1 = new(); MultitonScope scope1 = new();
MultitonScope scope2 = new(); MultitonScope scope2 = new();
ITest resolvedTest1 = _iocContainer.Resolve<ITest>(scope1); ITest resolvedTest1 = _iocContainer.Resolve<ITest>(scope1);
ITest resolvedTest2 = _iocContainer.Resolve<ITest>(scope1); ITest resolvedTest2 = _iocContainer.Resolve<ITest>(scope1);
ITest resolvedTest3 = _iocContainer.Resolve<ITest>(scope2); ITest resolvedTest3 = _iocContainer.Resolve<ITest>(scope2);
Assert.AreSame(resolvedTest1, resolvedTest2); Assert.AreSame(resolvedTest1, resolvedTest2);
Assert.AreNotSame(resolvedTest1, resolvedTest3); Assert.AreNotSame(resolvedTest1, resolvedTest3);
Assert.AreNotSame(resolvedTest2, resolvedTest3); Assert.AreNotSame(resolvedTest2, resolvedTest3);
} }
[Test] [Test]
public void TestResolveMultitonNoArgs() public void TestResolveMultitonNoArgs()
{ {
_iocContainer.Register(r => r.AddMultiton<ITest, Test, MultitonScope>()); _iocContainer.Register(r => r.AddMultiton<ITest, Test, MultitonScope>());
MultitonResolveException exception = Assert.Throws<MultitonResolveException>(() => _iocContainer.Resolve<ITest>()); MultitonResolveException exception = Assert.Throws<MultitonResolveException>(() => _iocContainer.Resolve<ITest>());
Assert.AreEqual(typeof(ITest), exception?.Type); Assert.AreEqual(typeof(ITest), exception?.Type);
} }
[Test] [Test]
public void TestResolveMultitonWrongArgs() public void TestResolveMultitonWrongArgs()
{ {
_iocContainer.Register(r => r.AddMultiton<ITest, Test, MultitonScope>()); _iocContainer.Register(r => r.AddMultiton<ITest, Test, MultitonScope>());
MultitonResolveException exception = Assert.Throws<MultitonResolveException>(() => _iocContainer.Resolve<ITest>(new object())); MultitonResolveException exception = Assert.Throws<MultitonResolveException>(() => _iocContainer.Resolve<ITest>(new object()));
Assert.AreEqual(typeof(ITest), exception?.Type); Assert.AreEqual(typeof(ITest), exception?.Type);
} }
[Test] [Test]
public void TestResolveTransient() public void TestResolveTransient()
{ {
_iocContainer.Register(r => r.Add<ITest, Test>()); _iocContainer.Register(r => r.Add<ITest, Test>());
ITest resolvedTest = _iocContainer.Resolve<ITest>(); ITest resolvedTest = _iocContainer.Resolve<ITest>();
ITest secondResolvedTest = _iocContainer.Resolve<ITest>(); ITest secondResolvedTest = _iocContainer.Resolve<ITest>();
Assert.AreNotEqual(resolvedTest, secondResolvedTest); Assert.AreNotEqual(resolvedTest, secondResolvedTest);
} }
[Test] [Test]
public void TestResolveNoMatchingConstructor() public void TestResolveNoMatchingConstructor()
{ {
_iocContainer.Register(r => r.Add<ITest, TestConstructor>()); _iocContainer.Register(r => r.Add<ITest, TestConstructor>());
NoMatchingConstructorFoundException exception = Assert.Throws<NoMatchingConstructorFoundException>(() => _iocContainer.Resolve<ITest>()); NoMatchingConstructorFoundException exception = Assert.Throws<NoMatchingConstructorFoundException>(() => _iocContainer.Resolve<ITest>());
Assert.AreEqual(typeof(TestConstructor), exception?.Type); Assert.AreEqual(typeof(TestConstructor), exception?.Type);
} }
[Test] [Test]
public void TestResolveNoMatchingConstructorNotThrownWrongly() public void TestResolveNoMatchingConstructorNotThrownWrongly()
{ {
_iocContainer.Register(r => r.Add<ITest, TestMultipleConstructors>()); _iocContainer.Register(r => r.Add<ITest, TestMultipleConstructors>());
Assert.DoesNotThrow(() => _iocContainer.Resolve<ITest>("Name")); Assert.DoesNotThrow(() => _iocContainer.Resolve<ITest>("Name"));
} }
[Test] [Test]
public void TestResolvePrivateConstructor() public void TestResolvePrivateConstructor()
{ {
_iocContainer.Register(r => r.Add<ITest, TestPrivateConstructor>()); _iocContainer.Register(r => r.Add<ITest, TestPrivateConstructor>());
NoPublicConstructorFoundException exception = Assert.Throws<NoPublicConstructorFoundException>(() => _iocContainer.Resolve<ITest>()); NoPublicConstructorFoundException exception = Assert.Throws<NoPublicConstructorFoundException>(() => _iocContainer.Resolve<ITest>());
Assert.AreEqual(typeof(TestPrivateConstructor), exception?.Type); Assert.AreEqual(typeof(TestPrivateConstructor), exception?.Type);
} }
[Test] [Test]
public void TestResolveSingleTypeRegistrationWithFactoryMethod() public void TestResolveSingleTypeRegistrationWithFactoryMethod()
{ {
_iocContainer.Register(r => r.Add<IFoo, Foo>()); _iocContainer.Register(r => r.Add<IFoo, Foo>());
_iocContainer.Register(r => r.Add<ITest>().WithFactoryMethod(c => new TestConstructor(c.Resolve<IFoo>(), "someName"))); _iocContainer.Register(r => r.Add<ITest>().WithFactoryMethod(c => new TestConstructor(c.Resolve<IFoo>(), "someName")));
ITest test = _iocContainer.Resolve<ITest>(); ITest test = _iocContainer.Resolve<ITest>();
Assert.NotNull(test); Assert.NotNull(test);
} }
[Test] [Test]
public void TestResolveParameterIsRegisteredWithParameters() public void TestResolveParameterIsRegisteredWithParameters()
{ {
_iocContainer.Register(r => r.Add<ITest, TestConstructor>()); _iocContainer.Register(r => r.Add<ITest, TestConstructor>());
_iocContainer.Register(r => r.Add<IFoo, FooConstructor>().WithParameters("TestString")); _iocContainer.Register(r => r.Add<IFoo, FooConstructor>().WithParameters("TestString"));
ITest test = _iocContainer.Resolve<ITest>("testName"); ITest test = _iocContainer.Resolve<ITest>("testName");
Assert.IsInstanceOf<TestConstructor>(test); Assert.IsInstanceOf<TestConstructor>(test);
} }
[Test] [Test]
public void TestResolveParameterWithParameterThatIsAlreadyExistingSingleton() public void TestResolveParameterWithParameterThatIsAlreadyExistingSingleton()
{ {
_iocContainer.Register(r => r.Add<ITest, TestWithFoo>()); _iocContainer.Register(r => r.Add<ITest, TestWithFoo>());
_iocContainer.Register(r => r.Add<IFoo, FooConstructor>(Lifestyle.Singleton).WithParameters("TestString")); _iocContainer.Register(r => r.Add<IFoo, FooConstructor>(Lifestyle.Singleton).WithParameters("TestString"));
IFoo foo = _iocContainer.Resolve<IFoo>(); IFoo foo = _iocContainer.Resolve<IFoo>();
ITest test = _iocContainer.Resolve<ITest>("testName"); ITest test = _iocContainer.Resolve<ITest>("testName");
Assert.IsInstanceOf<TestWithFoo>(test); Assert.IsInstanceOf<TestWithFoo>(test);
Assert.AreSame(foo, ((TestWithFoo) test).TestFoo); Assert.AreSame(foo, ((TestWithFoo) test).TestFoo);
} }
[Test] [Test]
public void TestIsTypeRegistered() public void TestIsTypeRegistered()
{ {
Assert.False(_iocContainer.IsTypeRegistered<ITest>()); Assert.False(_iocContainer.IsTypeRegistered<ITest>());
_iocContainer.Register(r => r.Add<ITest, Test>()); _iocContainer.Register(r => r.Add<ITest, Test>());
Assert.True(_iocContainer.IsTypeRegistered<ITest>()); Assert.True(_iocContainer.IsTypeRegistered<ITest>());
_iocContainer.Register(r => r.Add<Test>()); _iocContainer.Register(r => r.Add<Test>());
Assert.True(_iocContainer.IsTypeRegistered<Test>()); Assert.True(_iocContainer.IsTypeRegistered<Test>());
}
} }
} }

@ -12,177 +12,176 @@ using LightweightIocContainer.Validation;
using Moq; using Moq;
using NUnit.Framework; using NUnit.Framework;
namespace Test.LightweightIocContainer namespace Test.LightweightIocContainer;
[TestFixture]
public class IocValidatorTest
{ {
[TestFixture] public interface ITest
public class IocValidatorTest
{ {
public interface ITest
{
} }
public interface ITest2 public interface ITest2
{ {
} }
[UsedImplicitly] [UsedImplicitly]
public interface IParameter public interface IParameter
{ {
bool Method(); bool Method();
} }
private class Test : ITest private class Test : ITest
{ {
public Test(IParameter parameter) => parameter.Method(); public Test(IParameter parameter) => parameter.Method();
} }
[UsedImplicitly] [UsedImplicitly]
public interface ITestFactory public interface ITestFactory
{ {
ITest Create(IParameter parameter); ITest Create(IParameter parameter);
} }
[UsedImplicitly] [UsedImplicitly]
public interface ITest2Factory public interface ITest2Factory
{ {
ITest2 InvalidCreate(); ITest2 InvalidCreate();
ITest2 Create(ITest test); ITest2 Create(ITest test);
} }
private class Test2 : ITest2 private class Test2 : ITest2
{
public Test2(ITest parameter)
{ {
public Test2(ITest parameter)
{
}
} }
}
[UsedImplicitly] [UsedImplicitly]
public interface IInvalidFactory public interface IInvalidFactory
{ {
ITest Create(); ITest Create();
} }
private class TestInstallerNoFactory : IIocInstaller private class TestInstallerNoFactory : IIocInstaller
{ {
public void Install(IRegistrationCollector registration) => registration.Add<ITest, Test>(); public void Install(IRegistrationCollector registration) => registration.Add<ITest, Test>();
} }
private class TestInstallerWithFactory : IIocInstaller private class TestInstallerWithFactory : IIocInstaller
{ {
public void Install(IRegistrationCollector registration) => registration.Add<ITest, Test>().WithFactory<ITestFactory>(); public void Install(IRegistrationCollector registration) => registration.Add<ITest, Test>().WithFactory<ITestFactory>();
} }
private class TestInstallerWithInvalidFactory : IIocInstaller private class TestInstallerWithInvalidFactory : IIocInstaller
{ {
public void Install(IRegistrationCollector registration) => registration.Add<ITest, Test>().WithFactory<IInvalidFactory>(); public void Install(IRegistrationCollector registration) => registration.Add<ITest, Test>().WithFactory<IInvalidFactory>();
} }
private class InvalidTestClassInstaller : IIocInstaller private class InvalidTestClassInstaller : IIocInstaller
{
public void Install(IRegistrationCollector registration)
{ {
public void Install(IRegistrationCollector registration) registration.Add<ITest, Test>().WithFactory<ITestFactory>();
{ registration.Add<ITest2, Test2>().WithFactory<ITest2Factory>();
registration.Add<ITest, Test>().WithFactory<ITestFactory>();
registration.Add<ITest2, Test2>().WithFactory<ITest2Factory>();
}
} }
}
[Test] [Test]
public void TestValidateWithoutFactory() public void TestValidateWithoutFactory()
{ {
IocContainer iocContainer = new(); IocContainer iocContainer = new();
iocContainer.Install(new TestInstallerNoFactory()); iocContainer.Install(new TestInstallerNoFactory());
IocValidator validator = new(iocContainer); IocValidator validator = new(iocContainer);
AggregateException aggregateException = Assert.Throws<AggregateException>(() => validator.Validate()); AggregateException aggregateException = Assert.Throws<AggregateException>(() => validator.Validate());
AssertNoMatchingConstructorFoundForType<Test>(aggregateException); AssertNoMatchingConstructorFoundForType<Test>(aggregateException);
} }
[Test] [Test]
public void TestValidateWithFactory() public void TestValidateWithFactory()
{ {
IocContainer iocContainer = new(); IocContainer iocContainer = new();
iocContainer.Install(new TestInstallerWithFactory()); iocContainer.Install(new TestInstallerWithFactory());
IocValidator validator = new(iocContainer); IocValidator validator = new(iocContainer);
validator.Validate(); validator.Validate();
} }
[Test] [Test]
public void TestValidateWithParameter() public void TestValidateWithParameter()
{ {
IocContainer iocContainer = new(); IocContainer iocContainer = new();
iocContainer.Install(new TestInstallerNoFactory()); iocContainer.Install(new TestInstallerNoFactory());
IocValidator validator = new(iocContainer); IocValidator validator = new(iocContainer);
Mock<IParameter> parameterMock = new(); Mock<IParameter> parameterMock = new();
parameterMock.Setup(p => p.Method()).Returns(true); parameterMock.Setup(p => p.Method()).Returns(true);
validator.AddParameter<ITest, IParameter>(parameterMock.Object); validator.AddParameter<ITest, IParameter>(parameterMock.Object);
validator.Validate(); validator.Validate();
parameterMock.Verify(p => p.Method(), Times.Never); parameterMock.Verify(p => p.Method(), Times.Never);
} }
[Test] [Test]
public void TestValidateWithInvalidParameterWithFactory() public void TestValidateWithInvalidParameterWithFactory()
{ {
IocContainer iocContainer = new(); IocContainer iocContainer = new();
iocContainer.Install(new InvalidTestClassInstaller()); iocContainer.Install(new InvalidTestClassInstaller());
IocValidator validator = new(iocContainer); IocValidator validator = new(iocContainer);
Mock<IParameter> parameterMock = new(); Mock<IParameter> parameterMock = new();
validator.AddParameter<ITest, IParameter>(parameterMock.Object); validator.AddParameter<ITest, IParameter>(parameterMock.Object);
AggregateException aggregateException = Assert.Throws<AggregateException>(() => validator.Validate()); AggregateException aggregateException = Assert.Throws<AggregateException>(() => validator.Validate());
if (aggregateException?.InnerExceptions[0] is not NoMatchingConstructorFoundException noMatchingConstructorFoundException) if (aggregateException?.InnerExceptions[0] is not NoMatchingConstructorFoundException noMatchingConstructorFoundException)
{ {
Assert.Fail(); Assert.Fail();
return; return;
}
if (noMatchingConstructorFoundException.InnerExceptions[0] is not ConstructorNotMatchingException iTest2CtorNotMatchingException)
{
Assert.Fail();
return;
}
Assert.IsInstanceOf<DirectResolveWithRegisteredFactoryNotAllowed>(iTest2CtorNotMatchingException.InnerExceptions[0]);
} }
[Test] if (noMatchingConstructorFoundException.InnerExceptions[0] is not ConstructorNotMatchingException iTest2CtorNotMatchingException)
public void TestValidateInvalidFactory()
{ {
IocContainer iocContainer = new(); Assert.Fail();
iocContainer.Install(new TestInstallerWithInvalidFactory()); return;
}
IocValidator validator = new(iocContainer); Assert.IsInstanceOf<DirectResolveWithRegisteredFactoryNotAllowed>(iTest2CtorNotMatchingException.InnerExceptions[0]);
}
[Test]
public void TestValidateInvalidFactory()
{
IocContainer iocContainer = new();
iocContainer.Install(new TestInstallerWithInvalidFactory());
AggregateException aggregateException = Assert.Throws<AggregateException>(() => validator.Validate()); IocValidator validator = new(iocContainer);
AssertNoMatchingConstructorFoundForType<Test>(aggregateException); AggregateException aggregateException = Assert.Throws<AggregateException>(() => validator.Validate());
}
AssertNoMatchingConstructorFoundForType<Test>(aggregateException);
}
private void AssertNoMatchingConstructorFoundForType<T>(AggregateException aggregateException) private void AssertNoMatchingConstructorFoundForType<T>(AggregateException aggregateException)
{ {
Exception exception = aggregateException?.InnerExceptions[0]; Exception exception = aggregateException?.InnerExceptions[0];
if (exception is NoMatchingConstructorFoundException noMatchingConstructorFoundException) if (exception is NoMatchingConstructorFoundException noMatchingConstructorFoundException)
Assert.AreEqual(typeof(T), noMatchingConstructorFoundException.Type); Assert.AreEqual(typeof(T), noMatchingConstructorFoundException.Type);
else else
Assert.Fail($"Exception is no NoMatchingConstructorFoundException, actual type: {exception?.GetType()}"); Assert.Fail($"Exception is no NoMatchingConstructorFoundException, actual type: {exception?.GetType()}");
}
} }
} }

@ -6,96 +6,95 @@ using JetBrains.Annotations;
using LightweightIocContainer; using LightweightIocContainer;
using NUnit.Framework; using NUnit.Framework;
namespace Test.LightweightIocContainer namespace Test.LightweightIocContainer;
[TestFixture]
public class MultipleMultitonRegistrationTest
{ {
[TestFixture] private IocContainer _iocContainer;
public class MultipleMultitonRegistrationTest
{
private IocContainer _iocContainer;
[UsedImplicitly] [UsedImplicitly]
public interface ITest : IProvider public interface ITest : IProvider
{ {
} }
public interface IProvider public interface IProvider
{ {
int Number { get; } int Number { get; }
void DoSomething(int number); void DoSomething(int number);
} }
[UsedImplicitly] [UsedImplicitly]
public class Test : ITest public class Test : ITest
{ {
public int Number { get; private set; } public int Number { get; private set; }
public void DoSomething(int number) => Number = number; public void DoSomething(int number) => Number = number;
} }
private class MultitonScope private class MultitonScope
{ {
} }
[SetUp] [SetUp]
public void SetUp() => _iocContainer = new IocContainer(); public void SetUp() => _iocContainer = new IocContainer();
[TearDown] [TearDown]
public void TearDown() => _iocContainer.Dispose(); public void TearDown() => _iocContainer.Dispose();
[Test] [Test]
public void TestRegisterAndResolveMultipleMultitonRegistration() public void TestRegisterAndResolveMultipleMultitonRegistration()
{ {
_iocContainer.Register(r => r.AddMultiton<IProvider, ITest, Test, MultitonScope>()); _iocContainer.Register(r => r.AddMultiton<IProvider, ITest, Test, MultitonScope>());
MultitonScope scope = new(); MultitonScope scope = new();
ITest test = _iocContainer.Resolve<ITest>(scope); ITest test = _iocContainer.Resolve<ITest>(scope);
Assert.NotNull(test); Assert.NotNull(test);
IProvider provider = _iocContainer.Resolve<IProvider>(scope); IProvider provider = _iocContainer.Resolve<IProvider>(scope);
Assert.NotNull(provider); Assert.NotNull(provider);
Assert.AreEqual(test, provider); Assert.AreEqual(test, provider);
Assert.AreSame(test, provider); Assert.AreSame(test, provider);
} }
[Test] [Test]
public void TestRegisterAndResolveMultipleMultitonRegistrationWithDifferentScope() public void TestRegisterAndResolveMultipleMultitonRegistrationWithDifferentScope()
{ {
_iocContainer.Register(r => r.AddMultiton<IProvider, ITest, Test, MultitonScope>()); _iocContainer.Register(r => r.AddMultiton<IProvider, ITest, Test, MultitonScope>());
MultitonScope scope = new(); MultitonScope scope = new();
MultitonScope differentScope = new(); MultitonScope differentScope = new();
ITest test = _iocContainer.Resolve<ITest>(scope); ITest test = _iocContainer.Resolve<ITest>(scope);
Assert.NotNull(test); Assert.NotNull(test);
IProvider provider = _iocContainer.Resolve<IProvider>(differentScope); IProvider provider = _iocContainer.Resolve<IProvider>(differentScope);
Assert.NotNull(provider); Assert.NotNull(provider);
Assert.AreNotEqual(test, provider); Assert.AreNotEqual(test, provider);
Assert.AreNotSame(test, provider); Assert.AreNotSame(test, provider);
} }
[Test] [Test]
public void TestMultipleMultitonRegistrationOnCreate() public void TestMultipleMultitonRegistrationOnCreate()
{ {
_iocContainer.Register(r => r.AddMultiton<IProvider, ITest, Test, MultitonScope>().OnCreate(t => t.DoSomething(1))); _iocContainer.Register(r => r.AddMultiton<IProvider, ITest, Test, MultitonScope>().OnCreate(t => t.DoSomething(1)));
MultitonScope scope = new(); MultitonScope scope = new();
ITest test = _iocContainer.Resolve<ITest>(scope); ITest test = _iocContainer.Resolve<ITest>(scope);
Assert.NotNull(test); Assert.NotNull(test);
Assert.AreEqual(1, test.Number); Assert.AreEqual(1, test.Number);
IProvider provider = _iocContainer.Resolve<IProvider>(scope); IProvider provider = _iocContainer.Resolve<IProvider>(scope);
Assert.NotNull(provider); Assert.NotNull(provider);
Assert.AreEqual(1, provider.Number); Assert.AreEqual(1, provider.Number);
Assert.AreEqual(test, provider); Assert.AreEqual(test, provider);
Assert.AreSame(test, provider); Assert.AreSame(test, provider);
}
} }
} }

@ -9,31 +9,30 @@ using LightweightIocContainer.Registrations;
using Moq; using Moq;
using NUnit.Framework; using NUnit.Framework;
namespace Test.LightweightIocContainer namespace Test.LightweightIocContainer;
[TestFixture]
public class OnCreateTest
{ {
[TestFixture] private interface ITest
public class OnCreateTest
{ {
private interface ITest void DoSomething();
{ }
void DoSomething();
}
private class Test : ITest private class Test : ITest
{ {
public void DoSomething() => throw new Exception(); public void DoSomething() => throw new Exception();
} }
[Test] [Test]
public void TestOnCreate() public void TestOnCreate()
{ {
RegistrationFactory registrationFactory = new(new Mock<IocContainer>().Object); RegistrationFactory registrationFactory = new(new Mock<IocContainer>().Object);
ITypedRegistration<ITest, Test> testRegistration = registrationFactory.Register<ITest, Test>(Lifestyle.Transient).OnCreate(t => t.DoSomething()); ITypedRegistration<ITest, Test> testRegistration = registrationFactory.Register<ITest, Test>(Lifestyle.Transient).OnCreate(t => t.DoSomething());
Test test = new(); Test test = new();
Assert.Throws<Exception>(() => testRegistration.OnCreateAction!(test)); Assert.Throws<Exception>(() => testRegistration.OnCreateAction!(test));
}
} }
} }

@ -8,62 +8,61 @@ using LightweightIocContainer;
using LightweightIocContainer.Exceptions; using LightweightIocContainer.Exceptions;
using NUnit.Framework; using NUnit.Framework;
namespace Test.LightweightIocContainer namespace Test.LightweightIocContainer;
[TestFixture]
public class OpenGenericRegistrationTest
{ {
[TestFixture] private IocContainer _iocContainer;
public class OpenGenericRegistrationTest
{
private IocContainer _iocContainer;
[UsedImplicitly] [UsedImplicitly]
[SuppressMessage("ReSharper", "UnusedTypeParameter")] [SuppressMessage("ReSharper", "UnusedTypeParameter")]
public interface ITest<T> public interface ITest<T>
{ {
} }
[UsedImplicitly] [UsedImplicitly]
public class Test<T> : ITest<T> public class Test<T> : ITest<T>
{ {
} }
[SetUp] [SetUp]
public void SetUp() => _iocContainer = new IocContainer(); public void SetUp() => _iocContainer = new IocContainer();
[TearDown] [TearDown]
public void TearDown() => _iocContainer.Dispose(); public void TearDown() => _iocContainer.Dispose();
[Test] [Test]
public void TestRegisterOpenGenericType() public void TestRegisterOpenGenericType()
{ {
_iocContainer.Register(r => r.AddOpenGenerics(typeof(ITest<>), typeof(Test<>))); _iocContainer.Register(r => r.AddOpenGenerics(typeof(ITest<>), typeof(Test<>)));
ITest<int> test = _iocContainer.Resolve<ITest<int>>(); ITest<int> test = _iocContainer.Resolve<ITest<int>>();
Assert.NotNull(test); Assert.NotNull(test);
} }
[Test] [Test]
public void TestRegisterOpenGenericTypeAsSingleton() public void TestRegisterOpenGenericTypeAsSingleton()
{ {
_iocContainer.Register(r => r.AddOpenGenerics(typeof(ITest<>), typeof(Test<>), Lifestyle.Singleton)); _iocContainer.Register(r => r.AddOpenGenerics(typeof(ITest<>), typeof(Test<>), Lifestyle.Singleton));
ITest<int> test = _iocContainer.Resolve<ITest<int>>(); ITest<int> test = _iocContainer.Resolve<ITest<int>>();
Assert.NotNull(test); Assert.NotNull(test);
ITest<int> secondTest = _iocContainer.Resolve<ITest<int>>(); ITest<int> secondTest = _iocContainer.Resolve<ITest<int>>();
Assert.NotNull(secondTest); Assert.NotNull(secondTest);
Assert.AreEqual(test, secondTest); Assert.AreEqual(test, secondTest);
Assert.AreSame(test, secondTest); Assert.AreSame(test, secondTest);
} }
[Test] [Test]
public void TestRegisterOpenGenericTypeAsMultitonThrowsException() => public void TestRegisterOpenGenericTypeAsMultitonThrowsException() =>
Assert.Throws<InvalidRegistrationException>(() => _iocContainer.Register(r => r.AddOpenGenerics(typeof(ITest<>), typeof(Test<>), Lifestyle.Multiton))); Assert.Throws<InvalidRegistrationException>(() => _iocContainer.Register(r => r.AddOpenGenerics(typeof(ITest<>), typeof(Test<>), Lifestyle.Multiton)));
[Test] [Test]
public void TestRegisterNonOpenGenericTypeWithOpenGenericsFunctionThrowsException() => public void TestRegisterNonOpenGenericTypeWithOpenGenericsFunctionThrowsException() =>
Assert.Throws<InvalidRegistrationException>(() => _iocContainer.Register(r => r.AddOpenGenerics(typeof(int), typeof(int)))); Assert.Throws<InvalidRegistrationException>(() => _iocContainer.Register(r => r.AddOpenGenerics(typeof(int), typeof(int))));
}
} }

@ -10,90 +10,89 @@ using LightweightIocContainer.ResolvePlaceholders;
using Moq; using Moq;
using NUnit.Framework; using NUnit.Framework;
namespace Test.LightweightIocContainer namespace Test.LightweightIocContainer;
[TestFixture]
public class RegistrationBaseTest
{ {
[TestFixture] private interface ITest
public class RegistrationBaseTest
{ {
private interface ITest
{
} }
private interface IFoo private interface IFoo
{ {
} }
private interface IBar private interface IBar
{ {
} }
private class Test : ITest private class Test : ITest
{ {
} }
[UsedImplicitly] [UsedImplicitly]
private class Foo : IFoo private class Foo : IFoo
{
public Foo(IBar bar, ITest test)
{ {
public Foo(IBar bar, ITest test)
{
}
} }
}
private class Bar : IBar private class Bar : IBar
{ {
} }
[Test] [Test]
public void TestWithParameters() public void TestWithParameters()
{ {
RegistrationFactory registrationFactory = new(new Mock<IocContainer>().Object); RegistrationFactory registrationFactory = new(new Mock<IocContainer>().Object);
IBar bar = new Bar(); IBar bar = new Bar();
ITest test = new Test(); ITest test = new Test();
RegistrationBase testRegistration = (RegistrationBase) registrationFactory.Register<IFoo, Foo>(Lifestyle.Transient).WithParameters(bar, test); RegistrationBase testRegistration = (RegistrationBase) registrationFactory.Register<IFoo, Foo>(Lifestyle.Transient).WithParameters(bar, test);
Assert.AreEqual(bar, testRegistration.Parameters![0]); Assert.AreEqual(bar, testRegistration.Parameters![0]);
Assert.AreEqual(test, testRegistration.Parameters[1]); Assert.AreEqual(test, testRegistration.Parameters[1]);
} }
[Test] [Test]
public void TestWithParametersDifferentOrder() public void TestWithParametersDifferentOrder()
{ {
RegistrationFactory registrationFactory = new(new Mock<IocContainer>().Object); RegistrationFactory registrationFactory = new(new Mock<IocContainer>().Object);
IBar bar = new Bar(); IBar bar = new Bar();
ITest test = new Test(); ITest test = new Test();
RegistrationBase testRegistration = (RegistrationBase) registrationFactory.Register<IFoo, Foo>(Lifestyle.Transient).WithParameters((0, bar), (3, test), (2, "SomeString")); RegistrationBase testRegistration = (RegistrationBase) registrationFactory.Register<IFoo, Foo>(Lifestyle.Transient).WithParameters((0, bar), (3, test), (2, "SomeString"));
Assert.AreEqual(bar, testRegistration.Parameters![0]); Assert.AreEqual(bar, testRegistration.Parameters![0]);
Assert.IsInstanceOf<InternalResolvePlaceholder>(testRegistration.Parameters[1]); Assert.IsInstanceOf<InternalResolvePlaceholder>(testRegistration.Parameters[1]);
Assert.AreEqual("SomeString", testRegistration.Parameters[2]); Assert.AreEqual("SomeString", testRegistration.Parameters[2]);
Assert.AreEqual(test, testRegistration.Parameters[3]); Assert.AreEqual(test, testRegistration.Parameters[3]);
} }
[Test] [Test]
public void TestWithParametersCalledTwice() public void TestWithParametersCalledTwice()
{ {
RegistrationFactory registrationFactory = new(new Mock<IocContainer>().Object); RegistrationFactory registrationFactory = new(new Mock<IocContainer>().Object);
Assert.Throws<InvalidRegistrationException>(() => registrationFactory.Register<IFoo, Foo>(Lifestyle.Transient).WithParameters(new Bar()).WithParameters(new Test())); Assert.Throws<InvalidRegistrationException>(() => registrationFactory.Register<IFoo, Foo>(Lifestyle.Transient).WithParameters(new Bar()).WithParameters(new Test()));
Assert.Throws<InvalidRegistrationException>(() => registrationFactory.Register<IFoo, Foo>(Lifestyle.Transient).WithParameters((0, new Bar())).WithParameters((1, new Test()))); Assert.Throws<InvalidRegistrationException>(() => registrationFactory.Register<IFoo, Foo>(Lifestyle.Transient).WithParameters((0, new Bar())).WithParameters((1, new Test())));
} }
[Test] [Test]
public void TestWithParametersNoParametersGiven() public void TestWithParametersNoParametersGiven()
{ {
RegistrationFactory registrationFactory = new(new Mock<IocContainer>().Object); RegistrationFactory registrationFactory = new(new Mock<IocContainer>().Object);
Assert.Throws<InvalidRegistrationException>(() => registrationFactory.Register<IFoo, Foo>(Lifestyle.Transient).WithParameters((object[])null)); Assert.Throws<InvalidRegistrationException>(() => registrationFactory.Register<IFoo, Foo>(Lifestyle.Transient).WithParameters((object[])null));
Assert.Throws<InvalidRegistrationException>(() => registrationFactory.Register<IFoo, Foo>(Lifestyle.Transient).WithParameters(((int index, object parameter)[])null)); Assert.Throws<InvalidRegistrationException>(() => registrationFactory.Register<IFoo, Foo>(Lifestyle.Transient).WithParameters(((int index, object parameter)[])null));
}
} }
} }

@ -9,63 +9,62 @@ using LightweightIocContainer.Registrations;
using Moq; using Moq;
using NUnit.Framework; using NUnit.Framework;
namespace Test.LightweightIocContainer namespace Test.LightweightIocContainer;
[TestFixture]
// ReSharper disable MemberHidesStaticFromOuterClass
public class SingleTypeRegistrationTest
{ {
[TestFixture] private interface IFoo
// ReSharper disable MemberHidesStaticFromOuterClass
public class SingleTypeRegistrationTest
{ {
private interface IFoo IBar Bar { get; }
{ }
IBar Bar { get; }
}
private interface IBar private interface IBar
{ {
} }
[UsedImplicitly] [UsedImplicitly]
private class Foo : IFoo private class Foo : IFoo
{ {
public Foo(IBar bar) => Bar = bar; public Foo(IBar bar) => Bar = bar;
public IBar Bar { get; } public IBar Bar { get; }
} }
[UsedImplicitly] [UsedImplicitly]
private class Bar : IBar private class Bar : IBar
{ {
} }
[Test] [Test]
public void TestSingleTypeRegistrationWithFactoryMethod() public void TestSingleTypeRegistrationWithFactoryMethod()
{ {
IBar bar = new Bar(); IBar bar = new Bar();
Mock<IocContainer> iocContainerMock = new(); Mock<IocContainer> iocContainerMock = new();
iocContainerMock.Setup(c => c.Resolve<IBar>()).Returns(bar); iocContainerMock.Setup(c => c.Resolve<IBar>()).Returns(bar);
RegistrationFactory registrationFactory = new(iocContainerMock.Object); RegistrationFactory registrationFactory = new(iocContainerMock.Object);
ISingleTypeRegistration<IFoo> registration = registrationFactory.Register<IFoo>(Lifestyle.Transient).WithFactoryMethod(c => new Foo(c.Resolve<IBar>())); ISingleTypeRegistration<IFoo> registration = registrationFactory.Register<IFoo>(Lifestyle.Transient).WithFactoryMethod(c => new Foo(c.Resolve<IBar>()));
IFoo foo = registration.FactoryMethod!(iocContainerMock.Object); IFoo foo = registration.FactoryMethod!(iocContainerMock.Object);
Assert.AreEqual(bar, foo.Bar); Assert.AreEqual(bar, foo.Bar);
} }
[Test] [Test]
public void TestSingleTypeRegistrationResolveSingleton() public void TestSingleTypeRegistrationResolveSingleton()
{ {
IocContainer container = new(); IocContainer container = new();
IBar bar = new Bar(); IBar bar = new Bar();
container.Register(r => r.Add<IFoo>(Lifestyle.Singleton).WithFactoryMethod(_ => new Foo(bar))); container.Register(r => r.Add<IFoo>(Lifestyle.Singleton).WithFactoryMethod(_ => new Foo(bar)));
IFoo foo = container.Resolve<IFoo>(); IFoo foo = container.Resolve<IFoo>();
Assert.IsInstanceOf<Foo>(foo); Assert.IsInstanceOf<Foo>(foo);
Assert.AreEqual(bar, foo.Bar); Assert.AreEqual(bar, foo.Bar);
}
} }
} }
Loading…
Cancel
Save