/src/LinFu.IoC/Configuration/Extensions/ResolutionExtensions.cs

http://github.com/philiplaureano/LinFu · C# · 180 lines · 87 code · 23 blank · 70 comment · 7 complexity · 9e7deaad5cd0740abd3f21dff52888a7 MD5 · raw file

  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Reflection;
  6. using LinFu.Finders;
  7. using LinFu.IoC.Configuration.Interfaces;
  8. using LinFu.IoC.Interfaces;
  9. namespace LinFu.IoC.Configuration
  10. {
  11. /// <summary>
  12. /// Adds methods that extend LinFu.IoC to support automatic constructor resolution.
  13. /// </summary>
  14. public static class ResolutionExtensions
  15. {
  16. /// <summary>
  17. /// Generates a predicate that determines whether or not a specific parameter type
  18. /// exists in a container.
  19. /// </summary>
  20. /// <param name="parameterType">The target <see cref="Type" />. </param>
  21. /// <returns>
  22. /// A a predicate that determines whether or not a specific type
  23. /// exists in a container
  24. /// </returns>
  25. public static Func<IServiceContainer, bool> MustExistInContainer(this Type parameterType)
  26. {
  27. return container => container.Contains(parameterType);
  28. }
  29. /// <summary>
  30. /// Generates a predicate that determines whether or not a specific type is actually
  31. /// a list of services that can be created from a given container.
  32. /// </summary>
  33. /// <param name="parameterType">The target <see cref="Type" />. </param>
  34. /// <returns>
  35. /// A a predicate that determines whether or not a specific type
  36. /// exists as a list of services in a container
  37. /// </returns>
  38. public static Func<IServiceContainer, bool> ExistsAsEnumerableSetOfServices(this Type parameterType)
  39. {
  40. // The type must be derived from IEnumerable<T>
  41. var enumerableDefinition = typeof(IEnumerable<>);
  42. if (!parameterType.IsGenericType || parameterType.GetGenericTypeDefinition() != enumerableDefinition)
  43. return container => false;
  44. // Determine the individual service type
  45. var elementType = parameterType.GetGenericArguments()[0];
  46. var enumerableType = typeof(IEnumerable<>).MakeGenericType(elementType);
  47. // If this type isn't an IEnumerable<T> type, there's no point in testing
  48. // if it is a list of services that exists in the container
  49. if (!enumerableType.IsAssignableFrom(parameterType))
  50. return container => false;
  51. // A single service instance implies that a list of services can be created
  52. // from the current container
  53. Func<IServiceContainer, bool> hasService = container => container.Contains(elementType);
  54. // Check for any named services that can be included in the service list
  55. Func<IServiceContainer, bool> hasNamedService = container =>
  56. {
  57. var matches =
  58. (from info in container.AvailableServices
  59. where info.ServiceType == elementType
  60. select info).Count();
  61. return matches > 0;
  62. };
  63. return hasService.Or(hasNamedService);
  64. }
  65. /// <summary>
  66. /// Generates a predicate that determines whether or not a specific type is actually
  67. /// a list of services that can be created from a given container.
  68. /// </summary>
  69. /// <param name="parameterType">The target <see cref="Type" />. </param>
  70. /// <returns>
  71. /// A a predicate that determines whether or not a specific type
  72. /// exists as a list of services in a container
  73. /// </returns>
  74. public static Func<IServiceContainer, bool> ExistsAsServiceArray(this Type parameterType)
  75. {
  76. // The type must be an array
  77. if (!parameterType.IsArray)
  78. return container => false;
  79. var elementType = parameterType.GetElementType();
  80. // A single service instance implies that a list of services can be created
  81. // from the current container
  82. Func<IServiceContainer, bool> hasService = container => container.Contains(elementType);
  83. // Check for any named services that can be included in the service list
  84. Func<IServiceContainer, bool> hasNamedService = container =>
  85. {
  86. var matches =
  87. (from info in container.AvailableServices
  88. where info.ServiceType == elementType
  89. select info).Count();
  90. return matches > 0;
  91. };
  92. return hasService.Or(hasNamedService);
  93. }
  94. /// <summary>
  95. /// Builds an argument list for the <paramref name="method" />
  96. /// using the given <paramref name="container" /> instance.
  97. /// </summary>
  98. /// <param name="method">The method that will be used to instantiate an object instance.</param>
  99. /// <param name="container">The container that will provide the method arguments.</param>
  100. /// <returns>An array of objects to be used with the target method.</returns>
  101. public static object[] ResolveArgumentsFrom(this MethodBase method,
  102. IServiceContainer container)
  103. {
  104. var resolver = container.GetService<IArgumentResolver>();
  105. return resolver.ResolveFrom(method, container);
  106. }
  107. /// <summary>
  108. /// Builds an argument list for the target <paramref name="method" /> from
  109. /// services embedded inside the <paramref name="container" /> instance.
  110. /// </summary>
  111. /// <param name="resolver">The <see cref="IArgumentResolver" /> instance that will determine the method arguments.</param>
  112. /// <param name="method">The target method.</param>
  113. /// <param name="container">The container that will provide the method arguments.</param>
  114. /// <param name="additionalArguments">The additional arguments that will be passed to the target method.</param>
  115. /// <returns>An array of objects to be used with the target method.</returns>
  116. public static object[] ResolveFrom(this IArgumentResolver resolver, MethodBase method,
  117. IServiceContainer container, params object[] additionalArguments)
  118. {
  119. var parameterTypes = from p in method.GetParameters()
  120. select new NamedType(p) as INamedType;
  121. return resolver.ResolveFrom(parameterTypes, container, additionalArguments);
  122. }
  123. /// <summary>
  124. /// Casts an <see cref="IEnumerable" /> set of items into an array of
  125. /// <paramref name="targetElementType" /> items.
  126. /// </summary>
  127. /// <param name="items">The items being converted.</param>
  128. /// <param name="targetElementType">The element type of the resulting array.</param>
  129. /// <returns>An array of items that match the <paramref name="targetElementType" />.</returns>
  130. public static object Cast(this IEnumerable items, Type targetElementType)
  131. {
  132. var castMethodDefinition = typeof(ResolutionExtensions).GetMethod("Cast",
  133. BindingFlags.NonPublic |
  134. BindingFlags.Static);
  135. var castMethod = castMethodDefinition.MakeGenericMethod(targetElementType);
  136. var enumerable = items;
  137. var arguments = new object[] {enumerable};
  138. return castMethod.Invoke(null, arguments);
  139. }
  140. /// <summary>
  141. /// Performs a strongly typed cast against an <see cref="IEnumerable" /> instance.
  142. /// </summary>
  143. /// <typeparam name="T">The target element type.</typeparam>
  144. /// <param name="items">The list of items being converted.</param>
  145. /// <returns>An array of items that match the <typeparamref name="T" /> element type.</returns>
  146. private static T[] Cast<T>(IEnumerable items)
  147. {
  148. var results = new List<T>();
  149. foreach (var item in items)
  150. {
  151. var currentItem = (T) item;
  152. results.Add(currentItem);
  153. }
  154. return results.ToArray();
  155. }
  156. }
  157. }