Exemplo n.º 1
0
        /// <summary>
        /// Adds a service to the collection specifying what named dependencies to assign to named parameters.
        /// </summary>
        /// <typeparam name="TService">The type of service to add.</typeparam>
        /// <typeparam name="TImplementation">The implementation type for the service.</typeparam>
        /// <param name="serviceCollection">The collection of service descriptors.</param>
        /// <param name="lifetime">The lifetime of the service.</param>
        /// <param name="dependencies">
        /// The collection of named dependencies.
        /// {registeredType, registeredName, parameterName}
        /// </param>
        /// <returns>The <see cref="IServiceCollection"/>.</returns>
        public static IServiceCollection AddServiceWithNamedDependencies <TService, TImplementation>(
            this IServiceCollection serviceCollection,
            ServiceLifetime lifetime,
            params NamedDependency[] dependencies)
            where TImplementation : class
        {
            INamedServiceFactory[] factories = serviceCollection.Where(x => typeof(INamedServiceFactory).IsAssignableFrom(x.ServiceType))
                                               .Select(x => x.ImplementationInstance).Cast <INamedServiceFactory>().ToArray();

            // Gather a set of parameters from our target ttype that best match our named dependencies.
            ParameterInfo[] parameters = GetMatchingConstructorParameters <TImplementation>(out ConstructorInfo constructorInfo, dependencies);

            // Create an array of parameter factories that we can pass to our target factory.
            // We can reuse this for every request keeping overheads low and performance high.
            var argsFactory = new Func <IServiceProvider, object> [parameters.Length];

            for (int i = 0; i < parameters.Length; i++)
            {
                ParameterInfo parameter     = parameters[i];
                string        parameterName = parameter.Name;
                Type          parameterType = parameter.ParameterType;

                NamedDependency dependency = Array.Find(dependencies, x => x.ParameterName == parameterName && parameterType.IsAssignableFrom(x.ServiceType));
                if (dependency != default)
                {
                    INamedServiceFactory factory = Array.Find(factories, x => x.ServiceType == dependency.ServiceType);
                    if (factory != null)
                    {
                        argsFactory[i] = p => factory.Resolve(dependency.ServiceName, p);
                        continue;
                    }
                }

                argsFactory[i] = p => p.GetService(parameterType);
            }

            serviceCollection.Add(new ServiceDescriptor(typeof(TService), provider =>
            {
                object[] args = new object[argsFactory.Length];
                for (int i = 0; i < argsFactory.Length; i++)
                {
                    args[i] = argsFactory[i].Invoke(provider);
                }

                return(constructorInfo.Invoke(args));
            }, lifetime));

            return(serviceCollection);
        }
Exemplo n.º 2
0
        private static ParameterInfo[] GetMatchingConstructorParameters <T>(out ConstructorInfo constructorInfo, params NamedDependency[] dependencies)
        {
            int bestMatch = 0;

            constructorInfo = null;
            ParameterInfo[]   parameters       = Array.Empty <ParameterInfo>();
            ConstructorInfo[] constructorInfos = typeof(T).GetConstructors();

            // Loop through the constructors.
            // We look for the constructor that has largest number of matching parameters.
            for (int i = 0; i < constructorInfos.Length; i++)
            {
                int             currentMatch      = 0;
                ParameterInfo[] currentParameters = constructorInfos[i].GetParameters();
                for (int j = 0; j < currentParameters.Length; j++)
                {
                    ParameterInfo parameter = currentParameters[j];
                    for (int k = 0; k < dependencies.Length; k++)
                    {
                        NamedDependency dependency = dependencies[k];
                        if (parameter.Name == dependency.ParameterName &&
                            parameter.ParameterType.IsAssignableFrom(dependency.ServiceType))
                        {
                            currentMatch++;
                        }
                    }

                    if (currentMatch > bestMatch)
                    {
                        bestMatch       = currentMatch;
                        parameters      = currentParameters;
                        constructorInfo = constructorInfos[i];
                    }
                }
            }

            return(parameters);
        }