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

http://github.com/philiplaureano/LinFu · C# · 155 lines · 88 code · 22 blank · 45 comment · 19 complexity · 2b065ade93e32e005221c607712544f8 MD5 · raw file

  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using LinFu.Finders;
  6. using LinFu.IoC.Configuration.Interfaces;
  7. using LinFu.IoC.Interfaces;
  8. namespace LinFu.IoC.Configuration
  9. {
  10. /// <summary>
  11. /// Represents the default implementation of the <see cref="IArgumentResolver" /> class.
  12. /// </summary>
  13. public class ArgumentResolver : IArgumentResolver
  14. {
  15. /// <summary>
  16. /// Generates method arguments from the given <paramref name="parameterTypes" />
  17. /// and <paramref name="container" />.
  18. /// </summary>
  19. /// <param name="parameterTypes">The parameter types for the target method.</param>
  20. /// <param name="container">The container that will provide the method arguments.</param>
  21. /// <param name="additionalArguments">The additional arguments that will be passed to the target method.</param>
  22. /// <returns>An array of objects that represent the arguments to be passed to the target method.</returns>
  23. public object[] ResolveFrom(IEnumerable<INamedType> parameterTypes, IServiceContainer container,
  24. params object[] additionalArguments)
  25. {
  26. var enumerableDefinition = typeof(IEnumerable<>);
  27. var factoryDefinition = typeof(IFactory<>);
  28. var argumentList = new List<object>();
  29. foreach (var namedType in parameterTypes)
  30. {
  31. var parameterType = namedType.Type;
  32. // Use the named service instance if possible
  33. var parameterName = namedType.Name;
  34. string serviceName = null;
  35. if (!string.IsNullOrEmpty(parameterName) && parameterName.Length > 1)
  36. {
  37. var firstChar = parameterName.First().ToString();
  38. var remainingText = parameterName.Substring(1);
  39. serviceName = string.Format("{0}{1}", firstChar.ToUpper(), remainingText);
  40. }
  41. if (serviceName != null && container.Contains(serviceName, parameterType))
  42. {
  43. // Instantiate the service type and build
  44. // the argument list
  45. var currentArgument = container.GetService(serviceName, parameterType);
  46. argumentList.Add(currentArgument);
  47. continue;
  48. }
  49. // Substitute the parameter if and only if
  50. // the container does not have service that
  51. // that matches the parameter type
  52. var parameterTypeExists = container.Contains(parameterType);
  53. if (parameterTypeExists)
  54. {
  55. // Instantiate the service type and build
  56. // the argument list
  57. var currentArgument = container.GetService(parameterType);
  58. argumentList.Add(currentArgument);
  59. continue;
  60. }
  61. // Determine if the parameter type is an IEnumerable<T> type
  62. // and generate the list if necessary
  63. if (parameterType.IsGenericType &&
  64. parameterType.GetGenericTypeDefinition() == enumerableDefinition)
  65. {
  66. AddEnumerableArgument(parameterType, container, argumentList);
  67. continue;
  68. }
  69. if (parameterType.IsArray) AddArrayArgument(parameterType, container, argumentList);
  70. }
  71. // Append the existing arguments
  72. if (additionalArguments != null && additionalArguments.Length > 0)
  73. argumentList.AddRange(additionalArguments);
  74. return argumentList.ToArray();
  75. }
  76. /// <summary>
  77. /// Constructs an array of services using the services currently available
  78. /// in the <paramref name="container" />.
  79. /// </summary>
  80. /// <param name="parameterType">The current parameter type.</param>
  81. /// <param name="container">The container that will be used to build the array of services.</param>
  82. /// <param name="argumentList">The list that will store new service array.</param>
  83. private static void AddArrayArgument(Type parameterType, IServiceContainer container,
  84. ICollection<object> argumentList)
  85. {
  86. var isArrayOfServices = parameterType.ExistsAsServiceArray();
  87. if (!isArrayOfServices(container))
  88. return;
  89. var elementType = parameterType.GetElementType();
  90. // Instantiate all services that match
  91. // the element type
  92. var services = from info in container.AvailableServices
  93. where info.ServiceType == elementType
  94. select container.GetService(info);
  95. var serviceArray = services.Cast(elementType);
  96. argumentList.Add(serviceArray);
  97. }
  98. /// <summary>
  99. /// Determines whether or not a parameter type is an existing
  100. /// list of available services and automatically constructs the
  101. /// service list and adds it to the <paramref name="argumentList" />.
  102. /// </summary>
  103. /// <param name="parameterType">The current constructor parameter type.</param>
  104. /// <param name="container">The container that will provide the argument values.</param>
  105. /// <param name="argumentList">The list that will hold the arguments to be passed to the constructor.</param>
  106. private static void AddEnumerableArgument(Type parameterType, IServiceContainer container,
  107. ICollection<object> argumentList)
  108. {
  109. var elementType = parameterType.GetGenericArguments()[0];
  110. var baseElementDefinition = elementType.IsGenericType
  111. ? elementType.GetGenericTypeDefinition()
  112. : null;
  113. // There has to be at least one service
  114. Func<IServiceInfo, bool> condition =
  115. info => info.ServiceType == elementType;
  116. // If the element is a generic type,
  117. // we need to check for any available generic factory
  118. // instances that might be able to create the element type
  119. if (baseElementDefinition != null)
  120. condition = condition.Or(info => info.ServiceType == baseElementDefinition);
  121. if (!container.Contains(condition))
  122. return;
  123. var serviceList = new List<object>();
  124. // Build the IEnumerable<> list of services
  125. // that match the gvien condition
  126. var services = container.GetServices(condition);
  127. foreach (var service in services) serviceList.Add(service.Object);
  128. IEnumerable enumerable = serviceList.AsEnumerable();
  129. var result = enumerable.Cast(elementType);
  130. argumentList.Add(result);
  131. }
  132. }
  133. }