Exemple #1
0
        private ServiceCallSite TryCreateEnumerable(Type serviceType, CallSiteChain callSiteChain)
        {
            try
            {
                callSiteChain.Add(serviceType);

                if (serviceType.IsConstructedGenericType &&
                    serviceType.GetGenericTypeDefinition() == typeof(IEnumerable <>))
                {
                    var itemType = serviceType.GenericTypeArguments.Single();

                    var callSites = new List <ServiceCallSite>();

                    // If item type is not generic we can safely use descriptor cache
                    if (!itemType.IsConstructedGenericType &&
                        _descriptorLookup.TryGetValue(itemType, out var descriptors))
                    {
                        for (int i = 0; i < descriptors.Count; i++)
                        {
                            var descriptor = descriptors[i];

                            // Last service should get slot 0
                            var slot = descriptors.Count - i - 1;
                            // There may not be any open generics here
                            var callSite = TryCreateExact(descriptor, itemType, callSiteChain, slot);
                            Debug.Assert(callSite != null);

                            callSites.Add(callSite);
                        }
                    }
                    else
                    {
                        var slot = 0;
                        // We are going in reverse so the last service in descriptor list gets slot 0
                        for (var i = _descriptors.Count - 1; i >= 0; i--)
                        {
                            var descriptor = _descriptors[i];
                            var callSite   = TryCreateExact(descriptor, itemType, callSiteChain, slot) ??
                                             TryCreateOpenGeneric(descriptor, itemType, callSiteChain, slot);
                            slot++;
                            if (callSite != null)
                            {
                                callSites.Add(callSite);
                            }
                        }

                        callSites.Reverse();
                    }

                    return(new IEnumerableCallSite(itemType, callSites.ToArray()));
                }

                return(null);
            }
            finally
            {
                callSiteChain.Remove(serviceType);
            }
        }
Exemple #2
0
        private IServiceCallSite TryCreateEnumerable(Type serviceType, CallSiteChain callSiteChain)
        {
            if (serviceType.IsConstructedGenericType &&
                serviceType.GetGenericTypeDefinition() == typeof(IEnumerable <>))
            {
                var itemType = serviceType.GenericTypeArguments.Single();
                callSiteChain.Add(serviceType);

                var callSites = new List <IServiceCallSite>();

                // If item type is not generic we can safely use descriptor cache
                if (!itemType.IsConstructedGenericType &&
                    _descriptorLookup.TryGetValue(itemType, out var descriptors))
                {
                    for (int i = 0; i < descriptors.Count; i++)
                    {
                        var descriptor = descriptors[i];

                        // There may not be any open generics here
                        var callSite = TryCreateExact(descriptor, itemType, callSiteChain);
                        Debug.Assert(callSite != null);

                        callSites.Add(callSite);
                    }
                }
                else
                {
                    foreach (var descriptor in _descriptors)
                    {
                        var callSite = TryCreateExact(descriptor, itemType, callSiteChain) ??
                                       TryCreateOpenGeneric(descriptor, itemType, callSiteChain);

                        if (callSite != null)
                        {
                            callSites.Add(callSite);
                        }
                    }
                }

                return(new IEnumerableCallSite(itemType, callSites.ToArray()));
            }

            return(null);
        }
        /// <summary>
        /// 选择最优构造器并实例化ConstructorCallSite对象,
        /// </summary>
        /// <param name="lifetime"></param>
        /// <param name="serviceType"></param>
        /// <param name="implementationType"></param>
        /// <param name="callSiteChain"></param>
        /// <returns></returns>
        /// <exception cref="InvalidOperationException"></exception>
        private ServiceCallSite CreateConstructorCallSite(ResultCache lifetime, Type serviceType,
                                                          Type implementationType,
                                                          CallSiteChain callSiteChain)
        {
            //将此服务类型和实例类型存入callSiteChain
            callSiteChain.Add(serviceType, implementationType);

            //获取实例类型的所有公共构造器,然后选择其最优的构造器并创建ConstructorCallSite
            var constructors = implementationType.GetTypeInfo()
                               .DeclaredConstructors
                               .Where(constructor => constructor.IsPublic)
                               .ToArray();

            ServiceCallSite[] parameterCallSites = null;

            if (constructors.Length == 0)
            {
                //首先获取实例类型的所有公共构造器,如果不存在就抛出异常
                throw new InvalidOperationException(Resources.FormatNoConstructorMatch(implementationType));
            }
            else if (constructors.Length == 1)
            {
                //如果此类型只有一个构造器,那么就使用此构造器当做最优构造器进行实例化
                var constructor = constructors[0];
                var parameters  = constructor.GetParameters();
                if (parameters.Length == 0)
                {
                    return(new ConstructorCallSite(lifetime, serviceType, constructor));
                }

                //如果此类型具有多个构造器,那么就选出最优构造器
                parameterCallSites = CreateArgumentCallSites(
                    serviceType,
                    implementationType,
                    callSiteChain,
                    parameters,
                    throwIfCallSiteNotFound: true);

                return(new ConstructorCallSite(lifetime, serviceType, constructor, parameterCallSites));
            }

            // 如果没有找到最优构造器,就抛出异常,存在最优构造器就以此构造器实例化ConstructorCallSite
            Array.Sort(constructors,
                       (a, b) => b.GetParameters().Length.CompareTo(a.GetParameters().Length));

            ConstructorInfo bestConstructor = null;
            HashSet <Type>  bestConstructorParameterTypes = null;

            for (var i = 0; i < constructors.Length; i++)
            {
                var parameters = constructors[i].GetParameters();

                var currentParameterCallSites = CreateArgumentCallSites(
                    serviceType,
                    implementationType,
                    callSiteChain,
                    parameters,
                    throwIfCallSiteNotFound: false);

                if (currentParameterCallSites != null)
                {
                    if (bestConstructor == null)
                    {
                        bestConstructor    = constructors[i];
                        parameterCallSites = currentParameterCallSites;
                    }
                    else
                    {
                        // Since we're visiting constructors in decreasing order of number of parameters,
                        // we'll only see ambiguities or supersets once we've seen a 'bestConstructor'.

                        if (bestConstructorParameterTypes == null)
                        {
                            bestConstructorParameterTypes = new HashSet <Type>(
                                bestConstructor.GetParameters().Select(p => p.ParameterType));
                        }

                        if (!bestConstructorParameterTypes.IsSupersetOf(parameters.Select(p => p.ParameterType)))
                        {
                            // Ambiguous match exception
                            var message = string.Join(
                                Environment.NewLine,
                                Resources.FormatAmbiguousConstructorException(implementationType),
                                bestConstructor,
                                constructors[i]);
                            throw new InvalidOperationException(message);
                        }
                    }
                }
            }

            if (bestConstructor == null)
            {
                throw new InvalidOperationException(
                          Resources.FormatUnableToActivateTypeException(implementationType));
            }
            else
            {
                Debug.Assert(parameterCallSites != null);
                return(new ConstructorCallSite(lifetime, serviceType, bestConstructor, parameterCallSites));
            }
        }
        /// <summary>
        /// 服务类型是集合.那么将获取当前类型所有实现对象
        /// </summary>
        /// <param name="serviceType"></param>
        /// <param name="callSiteChain"></param>
        /// <returns></returns>
        private ServiceCallSite TryCreateEnumerable(Type serviceType, CallSiteChain callSiteChain)
        {
            //类型是封闭泛型类型并且泛型集合为IEnumerable
            if (serviceType.IsConstructedGenericType &&
                serviceType.GetGenericTypeDefinition() == typeof(IEnumerable <>))
            {
                //获取当前注册类型集合的泛型参数,由此类型来当基类类型进行获取注册当前类型的所有服务ServiceCallSite
                var itemType = serviceType.GenericTypeArguments.Single();
                callSiteChain.Add(serviceType);

                var callSites = new List <ServiceCallSite>();

                // If item type is not generic we can safely use descriptor cache
                if (!itemType.IsConstructedGenericType &&
                    _descriptorLookup.TryGetValue(itemType, out var descriptors))
                {
                    //如果泛型类型不是泛型并存在于缓存中
                    for (int i = 0; i < descriptors.Count; i++)
                    {
                        //一次获取其中每一个ServiceDecriptor然后创建对应的ServiceCallSite
                        var descriptor = descriptors[i];

                        //  设置当前slot
                        //   slot为倒序设置
                        // Last service should get slot 0
                        var slot = descriptors.Count - i - 1;
                        // There may not be any open generics here
                        //      获取当前ServiceDecriptor的ServiceCallSite并添加数组中

                        // There may not be any open generics here
                        var callSite = TryCreateExact(descriptor, itemType, callSiteChain, slot);
                        Debug.Assert(callSite != null);

                        callSites.Add(callSite);
                    }
                }
                else
                {
                    var slot = 0;
                    // We are going in reverse so the last service in descriptor list gets slot 0
                    for (var i = _descriptors.Count - 1; i >= 0; i--)
                    {
                        //遍历所有注册的ServiceDescriptor并获取对应的ServiceCallSite,然后如果不为空则添加至数组中
                        var descriptor = _descriptors[i];
                        var callSite   = TryCreateExact(descriptor, itemType, callSiteChain, slot) ??
                                         TryCreateOpenGeneric(descriptor, itemType, callSiteChain, slot);
                        slot++;
                        if (callSite != null)
                        {
                            callSites.Add(callSite);
                        }
                    }
                    //      反转集合元素

                    callSites.Reverse();
                }

                //  实例化IEnumerableCallSite并返回
                return(new IEnumerableCallSite(itemType, callSites.ToArray()));
            }

            return(null);
        }
Exemple #5
0
        private ServiceCallSite CreateConstructorCallSite(ResultCache lifetime, Type serviceType, Type implementationType,
                                                          CallSiteChain callSiteChain)
        {
            try
            {
                callSiteChain.Add(serviceType, implementationType);
                ConstructorInfo[] constructors = implementationType.GetTypeInfo()
                                                 .DeclaredConstructors
                                                 .Where(constructor => constructor.IsPublic)
                                                 .ToArray();

                ServiceCallSite[] parameterCallSites = null;

                if (constructors.Length == 0)
                {
                    throw new InvalidOperationException(SR.Format(SR.NoConstructorMatch, implementationType));
                }
                else if (constructors.Length == 1)
                {
                    ConstructorInfo constructor = constructors[0];
                    ParameterInfo[] parameters  = constructor.GetParameters();
                    if (parameters.Length == 0)
                    {
                        return(new ConstructorCallSite(lifetime, serviceType, constructor));
                    }

                    parameterCallSites = CreateArgumentCallSites(
                        serviceType,
                        implementationType,
                        callSiteChain,
                        parameters,
                        throwIfCallSiteNotFound: true);

                    return(new ConstructorCallSite(lifetime, serviceType, constructor, parameterCallSites));
                }

                Array.Sort(constructors,
                           (a, b) => b.GetParameters().Length.CompareTo(a.GetParameters().Length));

                ConstructorInfo bestConstructor = null;
                HashSet <Type>  bestConstructorParameterTypes = null;
                for (int i = 0; i < constructors.Length; i++)
                {
                    ParameterInfo[] parameters = constructors[i].GetParameters();

                    ServiceCallSite[] currentParameterCallSites = CreateArgumentCallSites(
                        serviceType,
                        implementationType,
                        callSiteChain,
                        parameters,
                        throwIfCallSiteNotFound: false);

                    if (currentParameterCallSites != null)
                    {
                        if (bestConstructor == null)
                        {
                            bestConstructor    = constructors[i];
                            parameterCallSites = currentParameterCallSites;
                        }
                        else
                        {
                            // Since we're visiting constructors in decreasing order of number of parameters,
                            // we'll only see ambiguities or supersets once we've seen a 'bestConstructor'.

                            if (bestConstructorParameterTypes == null)
                            {
                                bestConstructorParameterTypes = new HashSet <Type>(
                                    bestConstructor.GetParameters().Select(p => p.ParameterType));
                            }

                            if (!bestConstructorParameterTypes.IsSupersetOf(parameters.Select(p => p.ParameterType)))
                            {
                                // Ambiguous match exception
                                string message = string.Join(
                                    Environment.NewLine,
                                    SR.Format(SR.AmbiguousConstructorException, implementationType),
                                    bestConstructor,
                                    constructors[i]);
                                throw new InvalidOperationException(message);
                            }
                        }
                    }
                }

                if (bestConstructor == null)
                {
                    throw new InvalidOperationException(
                              SR.Format(SR.UnableToActivateTypeException, implementationType));
                }
                else
                {
                    Debug.Assert(parameterCallSites != null);
                    return(new ConstructorCallSite(lifetime, serviceType, bestConstructor, parameterCallSites));
                }
            }
            finally
            {
                callSiteChain.Remove(serviceType);
            }
        }
Exemple #6
0
        private ServiceCallSite TryCreateEnumerable(Type serviceType, CallSiteChain callSiteChain)
        {
            try
            {
                callSiteChain.Add(serviceType);

                if (serviceType.IsConstructedGenericType &&
                    serviceType.GetGenericTypeDefinition() == typeof(IEnumerable <>))
                {
                    Type itemType = serviceType.GenericTypeArguments[0];
                    CallSiteResultCacheLocation cacheLocation = CallSiteResultCacheLocation.Root;

                    var callSites = new List <ServiceCallSite>();

                    // If item type is not generic we can safely use descriptor cache
                    if (!itemType.IsConstructedGenericType &&
                        _descriptorLookup.TryGetValue(itemType, out ServiceDescriptorCacheItem descriptors))
                    {
                        for (int i = 0; i < descriptors.Count; i++)
                        {
                            ServiceDescriptor descriptor = descriptors[i];

                            // Last service should get slot 0
                            int slot = descriptors.Count - i - 1;
                            // There may not be any open generics here
                            ServiceCallSite callSite = TryCreateExact(descriptor, itemType, callSiteChain, slot);
                            Debug.Assert(callSite != null);

                            cacheLocation = GetCommonCacheLocation(cacheLocation, callSite.Cache.Location);
                            callSites.Add(callSite);
                        }
                    }
                    else
                    {
                        int slot = 0;
                        // We are going in reverse so the last service in descriptor list gets slot 0
                        for (int i = _descriptors.Count - 1; i >= 0; i--)
                        {
                            ServiceDescriptor descriptor = _descriptors[i];
                            ServiceCallSite   callSite   = TryCreateExact(descriptor, itemType, callSiteChain, slot) ??
                                                           TryCreateOpenGeneric(descriptor, itemType, callSiteChain, slot);

                            if (callSite != null)
                            {
                                slot++;

                                cacheLocation = GetCommonCacheLocation(cacheLocation, callSite.Cache.Location);
                                callSites.Add(callSite);
                            }
                        }

                        callSites.Reverse();
                    }


                    ResultCache resultCache = ResultCache.None;
                    if (cacheLocation == CallSiteResultCacheLocation.Scope || cacheLocation == CallSiteResultCacheLocation.Root)
                    {
                        resultCache = new ResultCache(cacheLocation, new ServiceCacheKey(serviceType, DefaultSlot));
                    }

                    return(new IEnumerableCallSite(resultCache, itemType, callSites.ToArray()));
                }

                return(null);
            }
            finally
            {
                callSiteChain.Remove(serviceType);
            }
        }
Exemple #7
0
        private ServiceCallSite CreateConstructorCallSite(ResultCache lifetime, Type serviceType, Type implementationType,
                                                          CallSiteChain callSiteChain)
        {
            callSiteChain.Add(serviceType, implementationType);

            var constructors = implementationType
                               .GetConstructors()
                               .Where(constructor => constructor.IsPublic)
                               .ToArray();

            ServiceCallSite[] parameterCallSites = null;

            if (constructors.Length == 0)
            {
                throw new InvalidOperationException(string.Format("A suitable constructor for type '{0}' could not be located. Ensure the type is concrete and services are registered for all parameters of a public constructor.", implementationType));
            }
            else if (constructors.Length == 1)
            {
                var constructor = constructors[0];
                var parameters  = constructor.GetParameters();
                if (parameters.Length == 0)
                {
                    return(new ConstructorCallSite(lifetime, serviceType, constructor));
                }

                parameterCallSites = CreateArgumentCallSites(
                    serviceType,
                    implementationType,
                    callSiteChain,
                    parameters,
                    throwIfCallSiteNotFound: true);

                return(new ConstructorCallSite(lifetime, serviceType, constructor, parameterCallSites));
            }

            Array.Sort(constructors,
                       (a, b) => b.GetParameters().Length.CompareTo(a.GetParameters().Length));

            ConstructorInfo bestConstructor = null;
            HashSet <Type>  bestConstructorParameterTypes = null;

            for (var i = 0; i < constructors.Length; i++)
            {
                var parameters = constructors[i].GetParameters();

                var currentParameterCallSites = CreateArgumentCallSites(
                    serviceType,
                    implementationType,
                    callSiteChain,
                    parameters,
                    throwIfCallSiteNotFound: false);

                if (currentParameterCallSites != null)
                {
                    if (bestConstructor == null)
                    {
                        bestConstructor    = constructors[i];
                        parameterCallSites = currentParameterCallSites;
                    }
                    else
                    {
                        // Since we're visiting constructors in decreasing order of number of parameters,
                        // we'll only see ambiguities or supersets once we've seen a 'bestConstructor'.

                        if (bestConstructorParameterTypes == null)
                        {
                            bestConstructorParameterTypes = new HashSet <Type>(
                                bestConstructor.GetParameters().Select(p => p.ParameterType));
                        }

                        if (!bestConstructorParameterTypes.IsSupersetOf(parameters.Select(p => p.ParameterType)))
                        {
                            // Ambiguous match exception
                            var message = string.Join(
                                Environment.NewLine,
                                string.Format("Unable to activate type '{0}'. The following constructors are ambiguous:", implementationType),
                                bestConstructor,
                                constructors[i]);
                            throw new InvalidOperationException(message);
                        }
                    }
                }
            }

            if (bestConstructor == null)
            {
                throw new InvalidOperationException(
                          string.Format("No constructor for type '{0}' can be instantiated using services from the service container and default values.", implementationType));
            }
            else
            {
                Debug.Assert(parameterCallSites != null);
                return(new ConstructorCallSite(lifetime, serviceType, bestConstructor, parameterCallSites));
            }
        }
        // 在这个方法中会选择服务实例类型中的最优构造器,并实例化一个ConstructorCallSite对象。
        private ServiceCallSite CreateConstructorCallSite(ResultCache lifetime, Type serviceType, Type implementationType,
                                                          CallSiteChain callSiteChain)
        {
            callSiteChain.Add(serviceType, implementationType);

            // 获取实例类型的所有公共构造器
            // 然后选择其最优的构造器并创建 ConstructorCallSite
            var constructors = implementationType.GetTypeInfo()
                               .DeclaredConstructors
                               .Where(constructor => constructor.IsPublic)
                               .ToArray();

            ServiceCallSite[] parameterCallSites = null;

            if (constructors.Length == 0)
            {
                // 没有公共构造器,直接抛出异常。
                throw new InvalidOperationException(Resources.FormatNoConstructorMatch(implementationType));
            }
            else if (constructors.Length == 1)
            {
                // 如果当前构造器为1个,则判断构造器是否存在参数并将所有参数进行实例化(创建指定的 ServiceCallSite)
                var constructor = constructors[0];
                // 获取当前构造器的所有参数,并对参数一一进行创建 ServiceCallSite 递归调用
                var parameters = constructor.GetParameters();
                if (parameters.Length == 0)
                {
                    // 如果构造器参数为0个,则直接为该服务实例类型创建 ConstructorCallSite
                    return(new ConstructorCallSite(lifetime, serviceType, constructor));
                }

                // 创建当前构造器的所有参数的 CallSite
                // 如果有未知的参数(_descriptorLookup 未记录的参数), 则直接抛出异常
                parameterCallSites = CreateArgumentCallSites(
                    serviceType,
                    implementationType,
                    callSiteChain,
                    parameters,
                    throwIfCallSiteNotFound: true);

                return(new ConstructorCallSite(lifetime, serviceType, constructor, parameterCallSites));
            }

            // 根据构造器参数的长度进行排序,下面会判断所有构造器中是否具有未知参数
            Array.Sort(constructors,
                       (a, b) => b.GetParameters().Length.CompareTo(a.GetParameters().Length));

            // 最优构造器
            ConstructorInfo bestConstructor = null;
            // 最优参数类型集合
            HashSet <Type> bestConstructorParameterTypes = null;

            for (var i = 0; i < constructors.Length; i++)
            {
                var parameters = constructors[i].GetParameters();

                // 创建当前构造器的所有参数的 CallSite
                // 如果具有未知的参数,则不抛出异常
                var currentParameterCallSites = CreateArgumentCallSites(
                    serviceType,
                    implementationType,
                    callSiteChain,
                    parameters,
                    throwIfCallSiteNotFound: false);

                if (currentParameterCallSites != null)
                {
                    // 如果所有参数的 CallSite 构造成功,并且最优构造函数对象为空,则将当前构造器设置为最优构造器。
                    if (bestConstructor == null)
                    {
                        bestConstructor    = constructors[i];
                        parameterCallSites = currentParameterCallSites;
                    }
                    else
                    {
                        if (bestConstructorParameterTypes == null)
                        {
                            // 如果最优参数类型集合为空,则将最优构造器的参数赋给集合。
                            bestConstructorParameterTypes = new HashSet <Type>(
                                bestConstructor.GetParameters().Select(p => p.ParameterType));
                        }

                        if (!bestConstructorParameterTypes.IsSupersetOf(parameters.Select(p => p.ParameterType)))
                        {
                            // 如果最优参数类型集合不为当前构造函数的参数集合的自己,则抛出异常
                            var message = string.Join(
                                Environment.NewLine,
                                Resources.FormatAmbiguousConstructorException(implementationType),
                                bestConstructor,
                                constructors[i]);
                            throw new InvalidOperationException(message);
                        }
                    }
                }
            }

            if (bestConstructor == null)
            {
                // 如果为找到最优构造函数,则抛出异常
                throw new InvalidOperationException(
                          Resources.FormatUnableToActivateTypeException(implementationType));
            }
            else
            {
                // 实例化一个 ConstructorCallSite 对象并返回。
                Debug.Assert(parameterCallSites != null);
                return(new ConstructorCallSite(lifetime, serviceType, bestConstructor, parameterCallSites));
            }
        }