PageRenderTime 94ms CodeModel.GetById 51ms app.highlight 8ms RepoModel.GetById 32ms app.codeStats 0ms

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