/src/LinFu.IoC/Configuration/Resolvers/MethodFinderFromContainer.cs

http://github.com/philiplaureano/LinFu · C# · 106 lines · 57 code · 13 blank · 36 comment · 4 complexity · 9d3e288600412901c15ee19fe8a95d32 MD5 · raw file

  1. using System.Collections.Generic;
  2. using System.Linq;
  3. using System.Reflection;
  4. using LinFu.Finders;
  5. using LinFu.Finders.Interfaces;
  6. using LinFu.IoC.Configuration.Interfaces;
  7. using LinFu.IoC.Interfaces;
  8. namespace LinFu.IoC.Configuration.Resolvers
  9. {
  10. /// <summary>
  11. /// A <see cref="MethodFinder{TMethod}" /> type that uses a <see cref="IServiceContainer" />
  12. /// instance to find a method with the most resolvable parameters.
  13. /// </summary>
  14. /// <typeparam name="TMethod">The method type that will be searched.</typeparam>
  15. public class MethodFinderFromContainer<TMethod> : MethodFinder<TMethod>, IMethodFinderWithContainer<TMethod>,
  16. IInitialize
  17. where TMethod : MethodBase
  18. {
  19. /// <summary>
  20. /// Initializes the target with the host container.
  21. /// </summary>
  22. /// <param name="container">The host <see cref="IServiceContainer" /> instance.</param>
  23. public void Initialize(IServiceContainer container)
  24. {
  25. Container = container;
  26. }
  27. /// <summary>
  28. /// Gets the value indicating the service container that will be used in the
  29. /// method search.
  30. /// </summary>
  31. public IServiceContainer Container { get; private set; }
  32. /// <summary>
  33. /// Examines a <see cref="ConstructorInfo" /> instance
  34. /// and determines if it can be instantiated with the services embedded in
  35. /// the target <paramref name="container" />.
  36. /// </summary>
  37. /// <param name="fuzzyItem">The <see cref="FuzzyItem{T}" /> that represents the constructor to be examined.</param>
  38. /// <param name="container">The container that contains the services that will be used to instantiate the target type.</param>
  39. /// <param name="maxIndex">
  40. /// Indicates the index that
  41. /// marks the point where the user-supplied arguments begin.
  42. /// </param>
  43. private static void CheckParameters(IFuzzyItem<TMethod> fuzzyItem,
  44. IServiceContainer container, int maxIndex)
  45. {
  46. var constructor = fuzzyItem.Item;
  47. var currentIndex = 0;
  48. foreach (var param in constructor.GetParameters())
  49. {
  50. if (currentIndex == maxIndex)
  51. break;
  52. var parameterType = param.ParameterType;
  53. var criteria = new Criteria<TMethod> {Type = CriteriaType.Critical, Weight = 1};
  54. // The type must either be an existing service
  55. // or a list of services that can be created from the container
  56. var predicate = parameterType.MustExistInContainer()
  57. .Or(parameterType.ExistsAsServiceArray())
  58. .Or(parameterType.ExistsAsEnumerableSetOfServices());
  59. criteria.Predicate = currentConstructor => predicate(container);
  60. fuzzyItem.Test(criteria);
  61. currentIndex++;
  62. }
  63. }
  64. /// <summary>
  65. /// Adds additional <see cref="ICriteria{T}" /> to the fuzzy search list.
  66. /// </summary>
  67. /// <param name="methods">The list of methods to rank.</param>
  68. /// <param name="finderContext">The <see cref="IMethodFinderContext" /> that describes the target method.</param>
  69. protected override void Rank(IList<IFuzzyItem<TMethod>> methods, IMethodFinderContext finderContext)
  70. {
  71. var additionalArguments = finderContext.Arguments ?? new object[0];
  72. var argumentTypes = (from argument in additionalArguments
  73. let argumentType = argument == null ? typeof(object) : argument.GetType()
  74. select argumentType).ToList();
  75. var argumentCount = argumentTypes.Count;
  76. foreach (var fuzzyItem in methods)
  77. {
  78. if (fuzzyItem.Confidence < 0)
  79. continue;
  80. // Check the constructor for any
  81. // parameter types that might not exist
  82. // in the container and eliminate the
  83. // constructor as a candidate match if
  84. // that parameter type cannot be found
  85. var constructor = fuzzyItem.Item;
  86. var parameters = constructor.GetParameters();
  87. var parameterCount = parameters.Length;
  88. var maxRelativeIndex = parameterCount - argumentCount;
  89. CheckParameters(fuzzyItem, Container, maxRelativeIndex);
  90. }
  91. }
  92. }
  93. }