PageRenderTime 252ms CodeModel.GetById 161ms app.highlight 7ms RepoModel.GetById 74ms app.codeStats 7ms

/src/LinFu.IoC/FactoryStorage.cs

http://github.com/philiplaureano/LinFu
C# | 163 lines | 82 code | 29 blank | 52 comment | 23 complexity | 29544547eabb6141f8ec6bbe2f05f458 MD5 | raw file
  1using System;
  2using LinFu.IoC.Factories;
  3using LinFu.IoC.Interfaces;
  4
  5namespace LinFu.IoC
  6{
  7    /// <summary>
  8    ///     Represents an <see cref="IFactoryStorage" /> instance that adds generics support to the
  9    ///     <see cref="BaseFactoryStorage" /> implementation.
 10    /// </summary>
 11    public class FactoryStorage : BaseFactoryStorage
 12    {
 13        /// <summary>
 14        ///     Determines whether or not an <see cref="IFactory" /> instance
 15        ///     can be used to create the given service described by the <paramref name="serviceInfo" /> object.
 16        /// </summary>
 17        /// <param name="serviceInfo">The <see cref="IServiceInfo" /> object that describes the service to be created.</param>
 18        /// <returns><c>True</c> if the service can be created; otherwise, it will return <c>false</c>.</returns>
 19        public override bool ContainsFactory(IServiceInfo serviceInfo)
 20        {
 21            var serviceType = serviceInfo.ServiceType;
 22            var serviceName = serviceInfo.ServiceName;
 23
 24            // Use the default implementation for
 25            // non-generic types
 26            if (!serviceType.IsGenericType && !serviceType.IsGenericTypeDefinition)
 27                return base.ContainsFactory(serviceInfo);
 28
 29            // If the service type is a generic type, determine
 30            // if the service type can be created by a 
 31            // standard factory that can create an instance
 32            // of that generic type (e.g., IFactory<IGeneric<T>>            
 33            var result = base.ContainsFactory(serviceInfo);
 34
 35            // Immediately return a positive match, if possible
 36            if (result)
 37                return true;
 38
 39            if (!serviceType.IsGenericType || serviceType.IsGenericTypeDefinition)
 40                return false;
 41
 42            // Determine the base type definition
 43            var baseDefinition = serviceType.GetGenericTypeDefinition();
 44
 45            // Check if there are any generic factories that can create
 46            // the entire family of services whose type definitions
 47            // match the base type
 48            var genericServiceInfo = new ServiceInfo(serviceName, baseDefinition, serviceInfo.ArgumentTypes);
 49            result = base.ContainsFactory(genericServiceInfo);
 50
 51            if (result)
 52                return true;
 53
 54            if (baseDefinition == typeof(IFactory<>))
 55            {
 56                var typeArguments = serviceType.GetGenericArguments();
 57                var actualServiceType = typeArguments[0];
 58
 59                var actualServiceInfo = new ServiceInfo(serviceName, actualServiceType, serviceInfo.ArgumentTypes);
 60                return base.ContainsFactory(actualServiceInfo);
 61            }
 62
 63            return false;
 64        }
 65
 66        /// <summary>
 67        ///     Obtains the <see cref="IFactory" /> instance that can instantiate the
 68        ///     service described by the <paramref name="serviceInfo" /> object instance.
 69        /// </summary>
 70        /// <param name="serviceInfo">The <see cref="IServiceInfo" /> object that describes the service to be created.</param>
 71        /// <returns>A <see cref="IFactory" /> instance if the service can be instantiated; otherwise, it will return <c>false</c>.</returns>
 72        public override IFactory GetFactory(IServiceInfo serviceInfo)
 73        {
 74            // Attempt to create the service type using
 75            // the strongly-typed arguments
 76            var factory = base.GetFactory(serviceInfo);
 77            var serviceType = serviceInfo.ServiceType;
 78            var serviceName = serviceInfo.ServiceName;
 79
 80            // Use the default factory for this service type if no other factory exists
 81            factory = GetDefaultFactory(serviceName, serviceType, factory);
 82
 83            // Attempt to create the service type using
 84            // the generic factories, if possible
 85            if (factory != null || !serviceType.IsGenericType)
 86                return factory;
 87
 88            var definitionType = serviceType.GetGenericTypeDefinition();
 89            var genericServiceInfo = new ServiceInfo(serviceName, definitionType, serviceInfo.ArgumentTypes);
 90
 91            // Find the generic factory that can specifically handle the given argument types
 92            var containsGenericFactory = base.ContainsFactory(genericServiceInfo);
 93            if (containsGenericFactory)
 94                return base.GetFactory(genericServiceInfo);
 95
 96            // Use the default generic factory if we can't match the given arguments
 97            var defaultGenericServiceInfo = new ServiceInfo(serviceName, definitionType);
 98            if (base.ContainsFactory(defaultGenericServiceInfo))
 99                return base.GetFactory(defaultGenericServiceInfo);
100
101
102            if (definitionType != typeof(IFactory<>))
103                return factory;
104
105            var typeArguments = serviceType.GetGenericArguments();
106            var actualServiceType = typeArguments[0];
107            factory = GetGenericFactory(serviceInfo, factory, serviceName, actualServiceType);
108
109            return factory;
110        }
111
112        /// <summary>
113        ///     Gets the default factory for a particular service type if no other factory instance can be found.
114        /// </summary>
115        /// <param name="serviceName">The name of the service.</param>
116        /// <param name="serviceType">The service type.</param>
117        /// <param name="factory">
118        ///     The original factory instance that was supposed to be created in order to instantiate the service
119        ///     instance.
120        /// </param>
121        /// <returns>The actual factory instance that will be used to create the service instance.</returns>
122        private IFactory GetDefaultFactory(string serviceName, Type serviceType, IFactory factory)
123        {
124            var defaultNamedServiceInfo = new ServiceInfo(serviceName, serviceType);
125            if (factory == null && base.ContainsFactory(defaultNamedServiceInfo))
126                factory = base.GetFactory(defaultNamedServiceInfo);
127
128            if (serviceType.IsGenericType)
129            {
130                var defaultServiceInfo = new ServiceInfo(string.Empty, serviceType);
131                if (factory == null && base.ContainsFactory(defaultServiceInfo))
132                    factory = base.GetFactory(defaultServiceInfo);
133            }
134
135
136            return factory;
137        }
138
139        /// <summary>
140        ///     Gets the generic factory for a concrete service type.
141        /// </summary>
142        /// <param name="serviceInfo">The <see cref="IServiceInfo" /> object that describes the service to be created.</param>
143        /// <param name="factory">The factory instance that will be used to create the service.</param>
144        /// <param name="serviceName">The name of the service.</param>
145        /// <param name="actualServiceType">The service type.</param>
146        /// <returns>A factory instance that can create the generic type.</returns>
147        private IFactory GetGenericFactory(IServiceInfo serviceInfo, IFactory factory, string serviceName,
148            Type actualServiceType)
149        {
150            var info = new ServiceInfo(serviceName, actualServiceType, serviceInfo.ArgumentTypes);
151
152            if (base.ContainsFactory(info))
153            {
154                var actualFactory = base.GetFactory(info);
155                Func<IFactoryRequest, object> factoryMethod = request => actualFactory;
156
157                factory = new FunctorFactory<IFactory>(factoryMethod);
158            }
159
160            return factory;
161        }
162    }
163}