PageRenderTime 54ms CodeModel.GetById 47ms app.highlight 4ms RepoModel.GetById 1ms app.codeStats 0ms

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