/src/LinFu.IoC/Configuration/FactoryBuilder.cs
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}