PageRenderTime 22ms CodeModel.GetById 15ms app.highlight 4ms RepoModel.GetById 1ms app.codeStats 0ms

/src/LinFu.IoC/Configuration/FactoryBuilder.cs

http://github.com/philiplaureano/LinFu
C# | 194 lines | 100 code | 32 blank | 62 comment | 10 complexity | 34098e626e753269aa41fef040c9a069 MD5 | raw file
  1using System;
  2using System.Collections.Generic;
  3using System.Reflection;
  4using LinFu.IoC.Configuration.Interfaces;
  5using LinFu.IoC.Factories;
  6using LinFu.IoC.Interfaces;
  7
  8namespace LinFu.IoC.Configuration
  9{
 10    /// <summary>
 11    ///     The default implementation of the <see cref="IFactoryBuilder" /> class.
 12    /// </summary>
 13    internal class FactoryBuilder : IFactoryBuilder
 14    {
 15        private static readonly Dictionary<LifecycleType, Type> _factoryTypes = new Dictionary<LifecycleType, Type>();
 16        private static readonly IServiceContainer _dummyContainer = new ServiceContainer();
 17
 18        /// <summary>
 19        ///     Initializes the list of factory types.
 20        /// </summary>
 21        static FactoryBuilder()
 22        {
 23            _factoryTypes[LifecycleType.OncePerRequest] = typeof(OncePerRequestFactory<>);
 24            _factoryTypes[LifecycleType.OncePerThread] = typeof(OncePerThreadFactory<>);
 25            _factoryTypes[LifecycleType.Singleton] = typeof(SingletonFactory<>);
 26        }
 27
 28
 29        /// <summary>
 30        ///     Creates a factory instance that can create instaces of the given
 31        ///     <paramref name="serviceType" />  using the <paramref name="implementingType" />
 32        ///     as the implementation.
 33        /// </summary>
 34        /// <param name="serviceType">The service being implemented.</param>
 35        /// <param name="implementingType">The actual type that will implement the service.</param>
 36        /// <param name="lifecycle">The <see cref="LifecycleType" /> that determines the lifetime of each instance being created.</param>
 37        /// <returns>A valid <see cref="IFactory" /> instance.</returns>
 38        public IFactory CreateFactory(Type serviceType, Type implementingType, LifecycleType lifecycle)
 39        {
 40            // Determine the factory type
 41            var factoryTypeDefinition = _factoryTypes[lifecycle];
 42
 43
 44            var actualType = GetActualType(serviceType, implementingType);
 45
 46            if (!serviceType.ContainsGenericParameters && !actualType.ContainsGenericParameters)
 47            {
 48                var factoryType = factoryTypeDefinition.MakeGenericType(serviceType);
 49                return CreateFactory(serviceType, actualType, factoryType);
 50            }
 51
 52            Func<IFactoryRequest, object> factoryMethod =
 53                request =>
 54                {
 55                    var serviceName = request.ServiceName;
 56                    var type = request.ServiceType;
 57                    var currentContainer = request.Container;
 58                    var arguments = request.Arguments;
 59
 60                    // Determine the implementing type
 61                    var concreteType = GetActualType(type, implementingType);
 62
 63                    // The concrete type cannot be null
 64                    if (concreteType == null)
 65                        return null;
 66
 67                    // Generate the concrete factory instance 
 68                    // at runtime
 69                    var factoryType = factoryTypeDefinition.MakeGenericType(type);
 70                    var factory = CreateFactory(type, concreteType, factoryType);
 71
 72                    var factoryRequest = new FactoryRequest
 73                    {
 74                        ServiceType = serviceType,
 75                        ServiceName = serviceName,
 76                        Arguments = arguments,
 77                        Container = currentContainer
 78                    };
 79
 80                    return factory.CreateInstance(factoryRequest);
 81                };
 82
 83            return new FunctorFactory(factoryMethod);
 84        }
 85
 86
 87        /// <summary>
 88        ///     Creates a factory instance that can create instaces of the given
 89        ///     <paramref name="serviceType" />  using the <paramref name="actualType" />
 90        ///     as the implementation.
 91        /// </summary>
 92        /// <param name="serviceType">The service being implemented.</param>
 93        /// <param name="actualType">The actual type that will implement the service.</param>
 94        /// <param name="factoryType">The factory type that will instantiate the target service.</param>
 95        /// <returns>A valid <see cref="IFactory" /> instance.</returns>
 96        private IFactory CreateFactory(Type serviceType, Type actualType, Type factoryType)
 97        {
 98            // Create the factory itself
 99            var factoryMethod = CreateFactoryMethod(serviceType, actualType);
100
101            var factoryInstance = factoryType.AutoCreateFrom(_dummyContainer, factoryMethod);
102            var result = factoryInstance as IFactory;
103
104            return result;
105        }
106
107        /// <summary>
108        ///     Determines the implementing concrete type from the given <paramref name="serviceType" />.
109        /// </summary>
110        /// <param name="serviceType">The service type.</param>
111        /// <param name="implementingType">The concrete class that will implement the service type.</param>
112        /// <returns>The actual implementing type.</returns>
113        private static Type GetActualType(Type serviceType, Type implementingType)
114        {
115            if (!implementingType.ContainsGenericParameters)
116                return implementingType;
117
118            var actualType = implementingType;
119
120            // The service type must be a generic type with
121            // closed generic parameters
122            if (!serviceType.IsGenericType || serviceType.ContainsGenericParameters)
123                return implementingType;
124
125
126            // Attempt to apply the generic parameters of the service type
127            // to the implementing type
128            var typeParameters = serviceType.GetGenericArguments();
129            try
130            {
131                var concreteType = implementingType.MakeGenericType(typeParameters);
132
133                // The concrete type must derive from the given service type
134                if (serviceType.IsAssignableFrom(concreteType))
135                    actualType = concreteType;
136            }
137            catch
138            {
139                // Ignore the error
140            }
141
142            return actualType;
143        }
144
145        /// <summary>
146        ///     A <c>private</c> method that creates the factory method delegate
147        ///     for use with a particular factory class.
148        /// </summary>
149        /// <seealso cref="SingletonFactory{T}" />
150        /// <seealso cref="OncePerRequestFactory{T}" />
151        /// <seealso cref="OncePerThreadFactory{T}" />
152        /// <param name="serviceType">The service type being instantiated.</param>
153        /// <param name="implementingType">The type that will provide the implementation for the actual service.</param>
154        /// <returns>A factory method delegate that can create the given service.</returns>
155        private MulticastDelegate CreateFactoryMethod(Type serviceType, Type implementingType)
156        {
157            var flags = BindingFlags.NonPublic | BindingFlags.Static;
158
159            var factoryMethodDefinition = typeof(FactoryBuilder).GetMethod("CreateFactoryMethodInternal", flags);
160            var factoryMethod = factoryMethodDefinition.MakeGenericMethod(serviceType, implementingType);
161
162            // Create the Func<IFactoryRequest, TService> factory delegate
163            var result = factoryMethod.Invoke(null, new object[0]) as MulticastDelegate;
164
165            return result;
166        }
167
168        /// <summary>
169        ///     A method that generates the actual lambda function that creates
170        ///     the new service instance.
171        /// </summary>
172        /// <typeparam name="TService">The service type being instantiated.</typeparam>
173        /// <typeparam name="TImplementation">The type that will provide the implementation for the actual service.</typeparam>
174        /// <returns>A strongly-typed factory method delegate that can create the given service.</returns>
175        internal static Func<IFactoryRequest, TService> CreateFactoryMethodInternal<TService, TImplementation>()
176            where TImplementation : TService
177        {
178            return request =>
179            {
180                var container = request.Container;
181                var arguments = request.Arguments;
182                var serviceContainer = container;
183
184                // Attempt to autoresolve the constructor
185                if (serviceContainer != null)
186                    return
187                        (TService) serviceContainer.AutoCreateInternal(typeof(TImplementation), arguments);
188
189                // Otherwise, use the default constructor
190                return (TService) Activator.CreateInstance(typeof(TImplementation), arguments);
191            };
192        }
193    }
194}