前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Core官方DI解析(3)-ServiceCallSite

Core官方DI解析(3)-ServiceCallSite

原创
作者头像
莫问今朝
发布2018-11-28 14:25:32
8340
发布2018-11-28 14:25:32
举报
文章被收录于专栏:博客园

上一篇说过在整个DI框架中IServiceProviderEngine是核心,但是如果直接看IServiceProviderEngine派生类其实看不出也没什么东西,因为这个类型其实都是调用的其它对象方法,所以我们先来看看其它的类型

ServiceCallSite

ServiceCallSite

代码语言:txt
复制
这个是一个服务访问配置的类型,DI内部使用此类的派生类型进行封装所需要实例化的信息然后进行实例化服务对象,首先我们先来看一下`ServiceCallSite`这个类所拥有的属性。从下面可以看到`ServiceCallSite`具有三个抽象属性和一个非抽象属性,其中\*\*ServiceType\*\*和\*\*ImplementationType\*\*已经知道代表注册的服务类型和实例对象的类型,

**Kind**是一个CallSiteKind枚举类型,代表的是当前CallSite所属的类型,,而**Cache**属性代表着服务实例对象的缓存配置

代码语言:txt
复制
internal abstract class ServiceCallSite

{

     protected ServiceCallSite(ResultCache cache)

     {

          Cache = cache;

     }

     //      当前注册的服务类型

     public abstract Type ServiceType { get; }

     //        当前注册的实例化类型

     public abstract Type ImplementationType { get; }

     //      当前CallSite所属的类型

     public abstract CallSiteKind Kind { get; }

    //       服务实例对象的缓存配置

     public ResultCache Cache { get; }

}

**ResultCache和ServiceCacheKey类型**

代码语言:txt
复制
internal struct ResultCache

{

     //        默认ResultCache  

     public static ResultCache None { get; } = new ResultCache(CallSiteResultCacheLocation.None, ServiceCacheKey.Empty);

     internal ResultCache(CallSiteResultCacheLocation lifetime, ServiceCacheKey cacheKey)

     {

          Location = lifetime;

          Key = cacheKey;

     }

    

     public ResultCache(ServiceLifetime lifetime, Type type, int slot)

     {

          switch (lifetime)

          {

               case ServiceLifetime.Singleton:

                    Location = CallSiteResultCacheLocation.Root;

                    break;

               case ServiceLifetime.Scoped:

                    Location = CallSiteResultCacheLocation.Scope;

                    break;

               case ServiceLifetime.Transient:

                    Location = CallSiteResultCacheLocation.Dispose;

                    break;

               default:

                    Location = CallSiteResultCacheLocation.None;

                    break;

          }

          Key = new ServiceCacheKey(type, slot);

     }

     //      当前服务实例缓存位置

     public CallSiteResultCacheLocation Location { get; set; }

     ///     当前服务实例所缓存的使用Key

     ///     ServiceCacheKey使用基类类型和一个solt(一个数值,每实例化同一个基类类型时使用不同的solt)

     public ServiceCacheKey Key { get; set; }

}



//    缓存实例对象时使用Key 

 internal struct ServiceCacheKey: IEquatable<ServiceCacheKey>

    {

        public static ServiceCacheKey Empty { get; } = new ServiceCacheKey(null, 0);

        //        注册服务类型

        public Type Type { get; }

        //      以IEnumerable类型解析时服务的反向索引,默认实例0

        //      相同Type时此值为++

        public int Slot { get; }

        public ServiceCacheKey(Type type, int slot)

        {

            Type = type;

            Slot = slot;

        }

        public bool Equals(ServiceCacheKey other)

        {

            return Type == other.Type && Slot == other.Slot;

        }

        public override int GetHashCode()

        {

            unchecked

            {

                return (Type.GetHashCode() \* 397) ^ Slot;

            }

        }

    }

ServiceCallSite

ServiceCallSite具有6个派生类型,分别是

* ConstantCallSite 服务注册是以单例模式以具体实例注册时使用

* ConstructorCallSite 服务注册是以类型注册,也就是实例化对象时以构造函数实例化

* FactoryCallSite 服务注册是以以工厂形式

* IEnumerableCallSite 这个时调用获取当前注册类型的所有实例,也就是GetServices()时

* ServiceProviderCallSite 这个

* ServiceScopeFactoryCallSite 这个是获取子容器所使用,在**Engine**类中会注册此类实例,然后获取子类容器使用

代码语言:txt
复制
这六个派生类中`ConstantCallSite`,`IEnumerableCallSite`,`ServiceProviderCallSite`和`ServiceScopeFactoryCallSite`这四个类的\*\*ResultCache\*\*属性使用的是\*\*None\*\*,而`ConstructorCallSite`和`FactoryCallSite `的\*\*ResultCache\*\*属性则由构造器传入,具体则有其服务注册的生命周期进行实例化\*\*ResultCache\*\*

] 在这里看一下ConstantCallSite,ConstructorCallSite,IEnumerableCallSiteServiceScopeFactoryCallSite这四个类

ConstantCallSite

代码语言:txt
复制
既然`ConstantCallSite`是具体实例注册的,所以此类中具有一个实例对象属性,由下面代码可以看出在构造此类实例时传入实例值,然后赋值给\*\*DefaultValue\*\*属性,这个类型也是这些派生类中唯一一个拥有具体实例的,
代码语言:txt
复制
然后\*\*Kind\*\*这个属性可以看到被赋值成了\*\*CallSiteKind.Constant\*\*,前面说过这个属性相当于代表此类型的属性,其它派生类都具有相应的枚举值    
代码语言:txt
复制
internal class ConstantCallSite : ServiceCallSite

    {

        /// <summary>

        ///     注册时提供的具体实例对象值

        /// </summary>

       internal object DefaultValue { get; }



        public ConstantCallSite(Type serviceType, object defaultValue): base(ResultCache.None)

        {

            DefaultValue = defaultValue;

        }

        /// <summary>

        ///     注册的基类类型

        /// </summary>

        public override Type ServiceType => DefaultValue.GetType();

        /// <summary>

        ///     其实际对象所对应的类型

        /// </summary>

        public override Type ImplementationType => DefaultValue.GetType();

        /// <summary>

        ///     当前ServiceCallSite所对应的类型

        /// </summary>

        public override CallSiteKind Kind { get; } = CallSiteKind.Constant;

    }

ConstructorCallSite

代码语言:txt
复制
这个类中具有两个主要属性

ConstructorInfo:当前选中的最优构造器

ParameterCallSites:构造参数数组

代码语言:txt
复制
internal class ConstructorCallSite : ServiceCallSite

{

     ///     实例化对象时所使用的构造器,当前构造器的最优构造器

     internal ConstructorInfo ConstructorInfo { get; }

     ///     当前构造器中所有参数的ServiceCallSite集合

     internal ServiceCallSite[] ParameterCallSites { get; }

     

     //        最优构造器为无参

     public ConstructorCallSite(ResultCache cache, Type serviceType, ConstructorInfo constructorInfo) : this(cache, serviceType, constructorInfo, Array.Empty<ServiceCallSite>())

     {}

     

     public ConstructorCallSite(ResultCache cache, Type serviceType, ConstructorInfo constructorInfo, ServiceCallSite[] parameterCallSites) : base(cache)

     {

          ServiceType = serviceType;

          ConstructorInfo = constructorInfo;

          ParameterCallSites = parameterCallSites;

     }

     public override Type ServiceType { get; }

     //        使用构造器的DeclaringType

     public override Type ImplementationType => ConstructorInfo.DeclaringType;

     public override CallSiteKind Kind { get; } = CallSiteKind.Constructor;

}

IEnumerableCallSite

代码语言:txt
复制
`IEnumerableCallSite`前面说过是对应的获取所有服务的访问设置类型,从下面代码可以看出其实这个类就是内部维护了一个`ServiceCallSite`数组和一个\*\*ItemType\*\*(这个代表真实的基类类型),并且要求实例对象时进行传入,然后最后实例化对象时遍历数组即可
代码语言:txt
复制
internal class IEnumerableCallSite : ServiceCallSite

    {

        /// <summary>

        ///     当前注册的类型  (基类类型)

        /// </summary>

        internal Type ItemType { get; }

        /// <summary>

        ///     所有服务的ServiceCallSite数组

        /// </summary>

        internal ServiceCallSite[] ServiceCallSites { get; }



        public IEnumerableCallSite(Type itemType, ServiceCallSite[] serviceCallSites) : base(ResultCache.None)

        {

            ItemType = itemType;

            ServiceCallSites = serviceCallSites;

        }



        public override Type ServiceType => typeof(IEnumerable<>).MakeGenericType(ItemType);

        public override Type ImplementationType  => ItemType.MakeArrayType();

        //        当前类型是IEnumberable标志

        public override CallSiteKind Kind { get; } = CallSiteKind.IEnumerable;

    }

ServiceScopeFactoryCallSite

代码语言:txt
复制
这个类型是子容器的工厂类型,下面代码中看到\*\*ImplementationType\*\*是一个`ServiceProviderEngine`类型,其实这个引擎类不止实现了`IServiceProviderEngine`接口,还实现了`IServiceScopeFactory`
代码语言:txt
复制
internal class ServiceScopeFactoryCallSite : ServiceCallSite

    {

        public ServiceScopeFactoryCallSite() : base(ResultCache.None)

        {

        }



        public override Type ServiceType { get; } = typeof(IServiceScopeFactory);

        //      IServiceProviderEngine派生类型,这个类型也实现了IServiceScopeFactory接口,所以是一个子容器工厂类型

        public override Type ImplementationType { get; } = typeof(ServiceProviderEngine);

        public override CallSiteKind Kind { get; } = CallSiteKind.ServiceScopeFactory;

    }

ServiceDescriptorCacheItem

代码语言:txt
复制
从下面代码可以看出这是一个结构,这个结构是具有相同注册服务的所有`ServiceDescriptor`封装,在`CallSiteFactory`类中进行使用
代码语言:txt
复制
 private struct ServiceDescriptorCacheItem{}
代码语言:txt
复制
在此结构中,可以看到具有两个字段\*\*\_item\*\*属性和一个\*\*\_items\*\*集合属性,\*\*\_item\*\*属性代表相同注册服务的第一个`ServiceDescriptor`,而\*\*\_items\*\*则是除去第一个其它的`ServiceDescriptor`集合,我没看懂微软为什么要这么干

**_item**:代表此注册服务的第一个ServiceDescriptor

**_items**:此字段表示除去第一个的的所有ServiceDescriptor集合

代码语言:txt
复制
此结构中的\*\*Last\*\*和\*\*Count\*\*分别是获取缓存的最后一个元素和数量,因为第一个`ServiceDescriptor`是\*\*\_item\*\*属性,所以这两个属性都考虑了\*\*\_item\*\*,
代码语言:txt
复制
/// <summary>

///     获取其注册的最后一个ServiceDescripto

///     如果其\_items集合为空,则获取其\_item的值

/// </summary>

public ServiceDescriptor Last

{

     get

     {

          if (\_items != null && \_items.Count > 0)

              return \_items[\_items.Count - 1];

          return \_item;

     }

}

//     所有相同注册类型的数量,

//      因为第一个是\_item,所以需要1+\_items.Count

public int Count

{

     get

     {

         if (\_item == null)

             return 0;

         return 1 + (\_items?.Count ?? 0);

     }

}

public ServiceDescriptor this[int index]

{

     get

     {

          if (index >= Count)

               throw new ArgumentOutOfRangeException(nameof(index));

          if (index == 0)

               return \_item;

          return \_items[index - 1];

     }

}
代码语言:txt
复制
结构中只有一个\*\*And()\*\*方法,此方法是添加一个`ServiceDescriptor`,可以每次调用此方法时都会创建新的实例,
代码语言:txt
复制
//     将指定固定ServiceDescriptor添加到集合中

//     首先实例化一个新的 ServiceDescriptorCacheItem对象

//     如果当前对象\_item属性为空,则将当前参数作为新ServiceDescriptorCacheItem对象>item属性

//     如果当前对象\_item不为空,则当前的对象\_item作为新ServiceDescriptorCacheItem对象>item属性,并且将原对象集合赋值给新对象集合,并且将参数加入到新对象集合中,然后返回新对象,

//     也就是第一个加入的永远是\_item值,其后加入的放入集合中

public ServiceDescriptorCacheItem Add(ServiceDescriptor descriptor)

{

     var newCacheItem = new ServiceDescriptorCacheItem();

     if (\_item == null)

          newCacheItem.\_item = descriptor;

     else

     {

          newCacheItem.\_item = \_item;

          newCacheItem.\_items = \_items ?? new List<ServiceDescriptor>();

          newCacheItem.\_items.Add(descriptor);

     }

     return newCacheItem;

}

CallSiteFactory

代码语言:txt
复制
下面来看看`CallSiteFactory`这个类型,这是`ServiceCallSite`的工厂类型,内部根据`ServiceDescriptor`创建对应的`ServiceCallSite`,下面一点点来看看这个类型

下面代码中是CallSiteFactory类中的属性

DefaultSlot:此属性是默认的Slot,默认为0

_descriptors:此属性是缓存所有的ServiceDescriptor

_callSiteCache:ServiceCallSite的缓存集合

_descriptorLookup:ServiceDescriptorCacheItem缓存集合

代码语言:txt
复制
internal class CallSiteFactory

{

     //      默认的Slot为0,

     private const int DefaultSlot = 0;

     ///     存储所有注册服务类型

     private readonly List<ServiceDescriptor> \_descriptors;

     ///     ServiceCallSite缓存集合

     private readonly ConcurrentDictionary<Type, ServiceCallSite> \_callSiteCache = new ConcurrentDictionary<Type, ServiceCallSite>();

     

     ///     所有注册的服务缓存类型

     ///     其中以所注册基类类型分组包装为一个ServiceDescriptorCacheItem类型,然后以注册的基类类型为Key进行缓存

     private readonly Dictionary<Type, ServiceDescriptorCacheItem> \_descriptorLookup = new Dictionary<Type, ServiceDescriptorCacheItem>();

}
代码语言:txt
复制
从下面代码可以看到`CallSiteFactory`类型构造函数需要一个`IEnumerable<ServiceDescriptor> descriptors`,在构造函数中除了实例化`\_stackGuard`对象和缓存`\_descriptors`之外,还调用了一个\*\*Populate()\*\*方法,这个方法是初始化`\_descriptorLookup`缓存
代码语言:txt
复制
public CallSiteFactory(IEnumerable<ServiceDescriptor> descriptors)

{

     \_stackGuard = new StackGuard();

     \_descriptors = descriptors.ToList();

     //      调用此方法缓存ServiceDescriptorCacheItem

     Populate(descriptors);

}
代码语言:txt
复制
在\*\*Populate\*\*方法中,首先经过了一系列的判断,最进行缓存
代码语言:txt
复制
private void Populate(IEnumerable<ServiceDescriptor> descriptors)

{

     foreach (var descriptor in descriptors)

     {

          //      获取ServiceDescriptor对象中所注册的基类

          var serviceTypeInfo = descriptor.ServiceType.GetTypeInfo();

          if (serviceTypeInfo.IsGenericTypeDefinition)

          {

               // 如果当前基类是泛型类,

               //  那么如果其实际类型implementationTypeInfo类不是泛型类或者为抽象类,那么就抛出异常

               var implementationTypeInfo = descriptor.ImplementationType?.GetTypeInfo();

               if (implementationTypeInfo == null || !implementationTypeInfo.IsGenericTypeDefinition)

                    throw new ArgumentException(

                    Resources.FormatOpenGenericServiceRequiresOpenGenericImplementation(descriptor.ServiceType),

                    nameof(descriptors));



               if (implementationTypeInfo.IsAbstract || implementationTypeInfo.IsInterface)

                    throw new ArgumentException(

                    Resources.FormatTypeCannotBeActivated(descriptor.ImplementationType, descriptor.ServiceType));

          }

          else if (descriptor.ImplementationInstance == null && descriptor.ImplementationFactory == null)

          {

               //      如果当前基类不为泛型类

               //      那么如果其实际类型为泛型类或者是抽象类型,那么就抛出异常

               var implementationTypeInfo = descriptor.ImplementationType.GetTypeInfo();



               if (implementationTypeInfo.IsGenericTypeDefinition ||

                   implementationTypeInfo.IsAbstract ||

                   implementationTypeInfo.IsInterface)

                    throw new ArgumentException(

                    Resources.FormatTypeCannotBeActivated(descriptor.ImplementationType, descriptor.ServiceType));

          }

          //      使用其注册的基类为key,将此ServiceDescriptor缓存到Dictionary<Type, ServiceDescriptorCacheItem>集合中

          //      ServiceDescriptorCacheItem是一个存放了所有相同注册基类的ServiceDescripto

          //      ServiceDescriptorCacheItem中具有一个item属性和一个items集合

          //      item属性是注册的第一个此类型的ServiceDescripto

          var cacheKey = descriptor.ServiceType;

          //        由于ServiceDescriptorCacheItem是一个结构,所以不会异常

          \_descriptorLookup.TryGetValue(cacheKey, out var cacheItem);

          \_descriptorLookup[cacheKey] = cacheItem.Add(descriptor);

     }

}
代码语言:txt
复制
在此类中具有一个\*\*GetCallSite()\*\*方法,外部也是调用此方法进行获取`ServiceCallSite`,如果当前`ServiceCallSite`已被缓存,则直接获取缓存中数据,如果未缓存,则创建并缓存,从下面代码可以看到,如果未被缓存就调用\*\*CreateCallSite()\*\*进行创建
代码语言:txt
复制
当前函数中有一个`CallSiteChain`类型,这个类型是一个限制,应该是为了防止多线程,在创建之前进行了判断,如果已创建,则抛出异常,`CallSiteChain`这个类在此就不做介绍    
代码语言:txt
复制
internal ServiceCallSite GetCallSite(Type serviceType, CallSiteChain callSiteChain)

     => \_callSiteCache.GetOrAdd(serviceType, (type, chain) => CreateCallSite(type, chain), callSiteChain);
代码语言:txt
复制
在`CreateCallSite()`首先调用了`CallSiteChain`实例的\*\*CheckCircularDependency()\*\*方法,这个方法就是如果已被创建,则抛出异常.然后分别调用\*\*TryCreateExact()\*\*,\*\*TryCreateOpenGeneric()\*\*,\*\*TryCreateEnumerable()\*\*这三个方法进行尝试实例化`ServiceCallSite`,下面我们来看看这三个方法和它们依赖的方法
代码语言:txt
复制
private ServiceCallSite CreateCallSite(Type serviceType, CallSiteChain callSiteChain)

{

     ServiceCallSite callSite;

     try

     {

          //      检查是否已被创建,如果已创建,则抛出异常

          callSiteChain.CheckCircularDependency(serviceType);

          //      获取指定服务的实例对象方式

          //          1.首先创建普通类型的ServiceCallSite,

          //          2.创建泛型类型的ServiceCallSite

          //          3.如果服务类型是集合.那么将获取当前类型所有实现对象

          callSite = TryCreateExact(serviceType, callSiteChain) ??

               TryCreateOpenGeneric(serviceType, callSiteChain) ??

               TryCreateEnumerable(serviceType, callSiteChain);

     }

     finally

     {

          callSiteChain.Remove(serviceType);

     }

     \_callSiteCache[serviceType] = callSite;



     return callSite;

}
1.TryCreateExact()
代码语言:txt
复制
\*\*TryCreateExact()\*\*方法是如果\*ServiceType\*只是一个普通类型时才使用的方法,如下代码,首先判断了此类型是否存在于\*\*\_descriptorLookup\*\*缓存中,如果不存在直接返回null,如果存在的话直接使用\*\*最后一个ServiceDescriptor\*\*和\*\*DefaultSlot\*\*进行,这也就是为什么总是会获取最后一个服务实例的原因
代码语言:txt
复制
private ServiceCallSite TryCreateExact(Type serviceType, CallSiteChain callSiteChain)

{

     //      在\_descriptorLookup缓存中获取指定基类的所有ServiceDescriptor实例,

     //      然后利用最后一个ServiceDescriptor进行实例化ServiceCallSite

     if (\_descriptorLookup.TryGetValue(serviceType, out var descriptor))

         return TryCreateExact(descriptor.Last, serviceType, callSiteChain, DefaultSlot);

     return null;

}
代码语言:txt
复制
\*\*TryCreateExact()\*\*中则根据注册服务的方式进行实例化`ServiceCallSite`可以看到使用具体实例对象和工厂时直接实例化`ServiceCallSite`,而使用类型注册时则又调用\*\*CreateConstructorCallSite()\*\*进行实例化一个`ConstructorCallSite`对象
代码语言:txt
复制
private ServiceCallSite TryCreateExact(ServiceDescriptor descriptor, Type serviceType, CallSiteChain callSiteChain, int slot)

{

     //      判断基类类型是否与ServiceDescriptor所持有的基类类型是否一致,如果不一致直接返回false

     if (serviceType == descriptor.ServiceType)

     {

          ServiceCallSite callSite;

          //      根据当前注册的生命周期,基类类型和slot实例化一个ResultCache,

          //      ResultCache类型具有一个最后结果缓存的位置(相当于跟生命周期一致)和一个缓存Key

          var lifetime = new ResultCache(descriptor.Lifetime, serviceType, slot);

          //      根据注册时所使用的方式来创建不同的ServiceCallSite,共具有三种ServiceCallSite子类

          //      ConstantCallSite    注册时直接根据对象进行实例化具体对象(Singleton生命周期独有)

          //      FactoryCallSite     注册时根据一个工厂实例化对象

          //      ConstructorCallSite 注册时根据具体实例类型进行实例化对象

          if (descriptor.ImplementationInstance != null)

               callSite = new ConstantCallSite(descriptor.ServiceType, descriptor.ImplementationInstance);

          else if (descriptor.ImplementationFactory != null)

               callSite = new FactoryCallSite(lifetime, descriptor.ServiceType, descriptor.ImplementationFactory);

          else if (descriptor.ImplementationType != null)

               //      如果注册类型是使用的派生类类型方式,则调用CreateConstructorCallSite来实例化一个ConstructorCallSite

               callSite = CreateConstructorCallSite(lifetime, descriptor.ServiceType, descriptor.ImplementationType, callSiteChain);

          else

               throw new InvalidOperationException("Invalid service descriptor");

          return callSite;

     }

     return null;

}
代码语言:txt
复制
下面看一下\*\*CreateConstructorCallSite()\*\*这个方法,在这个方法中选择最优构造器并实例化`ConstructorCallSite`对象,

首先获取实例类型的所有公共构造器,如果不存在就抛出异常

如果此类型只有一个构造器,那么就使用此构造器当做最优构造器进行实例化,

如果此类型具有多个构造器,那么就选出最优构造器

如果没有找到最优构造器,就抛出异常,存在最优构造器就以此构造器实例化ConstructorCallSite

注:最优构造器是参数最多的构造器,但是如果其它构造器参数中具有最优构造器没有的参数,就抛出异常

代码语言:txt
复制
在此方法中如果最优构造器拥有参数,还会调用一个\*\*CreateArgumentCallSites()\*\*,这个方法会依次实例化参数的`ServiceCallSite`    
代码语言:txt
复制
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)

     {

          //     如果当前构造器为1个,则判断构造器是否存在参数并将所有参数进行实例化(创建指定的ServiceCallSite),

          var constructor = constructors[0];

          //      获取当前构造器的所有参数,并对参数一一进行创建ServiceCallSite  递归调用

          var parameters = constructor.GetParameters();

          if (parameters.Length == 0)

          {

               return new ConstructorCallSite(lifetime, serviceType, constructor);

          }

          //      创建当前构造器所有参数的ServiceCallSite

          //      如果具有未知的参数,则直接抛出异常

          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();

          //      创建当前构造器所有参数的ServiceCallSite

          //      如果具有未知的参数,则不抛出异常

          var currentParameterCallSites = CreateArgumentCallSites(

               serviceType,

               implementationType,

               callSiteChain,

               parameters,

               throwIfCallSiteNotFound: false);



          if (currentParameterCallSites != null)

          {

               //  如果所有参数的ServiceCallSite构造成功,并且当前最优构造器对象为空,则将当前构造器设置为最优构造器

               if (bestConstructor == null)

               {

                    bestConstructor = constructors[i];

                    parameterCallSites = currentParameterCallSites;

               }

               else

               {

                    if (bestConstructorParameterTypes == null)

                         //      如果最优参数类型集合为空,则将当前构造器的参数赋给集合

                         bestConstructorParameterTypes = new HashSet<Type>(

                         bestConstructor.GetParameters().Select(p => p.ParameterType));

                    //      如果bestConstructorParameterTypes为不为当前构造参数集合的子集,则抛出异常

                    //      子集指当前bestConstructorParameterTypes集合中所有数据是否在当前构造参数集合之中

                    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

          //      实例化一个ConstructorCallSite对象并返回

          return new ConstructorCallSite(lifetime, serviceType, bestConstructor, parameterCallSites);

}
代码语言:txt
复制
在\*\*CreateArgumentCallSites()\*\*中递归调用\*\*GetCallSite()\*\*获取每一个参数对应的`ServiceCallSite`,在方法中可以看到如果从\*\*GetCallSite()\*\*中未获取到对应的实例对象但是该参数具有默认参数,那么就使用默认参数.
代码语言:txt
复制
在这个方法有意思的是最后一个参数,最后一个参数如果为true,那么如果最终未获取到参数的`ServiceCallSite`就抛出一场,如果为false,就返回null    
代码语言:txt
复制
private ServiceCallSite[] CreateArgumentCallSites(

     Type serviceType,

     Type implementationType,

     CallSiteChain callSiteChain,

     ParameterInfo[] parameters,

     bool throwIfCallSiteNotFound)

{

     var parameterCallSites = new ServiceCallSite[parameters.Length];

     for (var index = 0; index < parameters.Length; index++)

     {

          //      依次递归调用获取指定参数的ServiceCallSite

          var callSite = GetCallSite(parameters[index].ParameterType, callSiteChain);

          if (callSite == null && ParameterDefaultValue.TryGetDefaultValue(parameters[index], out var defaultValue))

               //          如果获取参数的ServiceCallSite失败但是该参数具有默认值

               //          则直接以默认值来创建ConstantCallSite对象

               callSite = new ConstantCallSite(serviceType, defaultValue);

          //      如果当前callSite还为空,则代表出现无法实例化的参数类型

          //      如果允许抛出异常则抛出异常,如果不允许抛出异常则返回null

          if (callSite == null)

          {

               if (throwIfCallSiteNotFound)

                    throw new InvalidOperationException(Resources.FormatCannotResolveService(

                         parameters[index].ParameterType,

                         implementationType));

               return null;

          }



          parameterCallSites[index] = callSite;

     }

     return parameterCallSites;

}
2.TryCreateOpenGeneric()
代码语言:txt
复制
从下面代码可以看出\*\*TryCreateOpenGeneric()\*\*首先会判断此泛型是否是封闭类型并且此类型是否存在于\*\*\_descriptorLookup\*\*,然后调用\*\*TryCreateOpenGeneric()\*\*进行获取`ServiceCallSite`
代码语言:txt
复制
在\*\*TryCreateOpenGeneric()\*\*中则根据注册服务类型的泛型参数制造一个实现类型参数,然后调用\*\*CreateConstructorCallSite()\*\*进行实例化`ServiceCallSite`,所以泛型只能以构造器实例方式    
代码语言:txt
复制
private ServiceCallSite TryCreateOpenGeneric(Type serviceType, CallSiteChain callSiteChain)

{

     //      如果是泛型是封闭并且在\_descriptorLookup缓存集合中具有此类型的缓存

     if (serviceType.IsConstructedGenericType

         && \_descriptorLookup.TryGetValue(serviceType.GetGenericTypeDefinition(), out var descriptor))

            return TryCreateOpenGeneric(descriptor.Last, serviceType, callSiteChain, DefaultSlot);

     return null;

}



private ServiceCallSite TryCreateOpenGeneric(ServiceDescriptor descriptor, Type serviceType, CallSiteChain callSiteChain, int slot)

{

     //   如果当前泛型类型为封闭并且当前注册的基类类型为当前泛型的开放类型,则实例化,否则返回null

     if (serviceType.IsConstructedGenericType &&

         serviceType.GetGenericTypeDefinition() == descriptor.ServiceType)

     {

          //  利用当前注册服务的声明和生命周期类型实例化一个结果缓存配置

          var lifetime = new ResultCache(descriptor.Lifetime, serviceType, slot);

          //     利用注册类型泛型参数创造派生类封闭泛型类型

          var closedType = descriptor.ImplementationType.MakeGenericType(serviceType.GenericTypeArguments);

          //      创建一个ConstructorCallSite并返回

          return CreateConstructorCallSite(lifetime, serviceType, closedType, callSiteChain);

     }

     return null;

}
3.TryCreateEnumerable()
代码语言:txt
复制
最后我们来看看\*\*TryCreateEnumerable()\*\*这个方法,这个方法就是获取`IEnumerableCallSite`类型的,也就是获取当前注册类型所有实例时使用的,从下面代码可以看到如果IEnumerable的泛型参数不是泛型并且缓存于\*\*\_descriptorLookup\*\*集合中,就使用对应的所有的`ServiceProvider`进行实例化,如果二者有一不可就遍历\*\*\_descriptors\*\*实例`ServiceCallSite`
代码语言:txt
复制
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 (!itemType.IsConstructedGenericType &&

              \_descriptorLookup.TryGetValue(itemType, out var descriptors))

          {

               //  如果泛型类型不是泛型并存在于缓存中

               for (int i = 0; i < descriptors.Count; i++)

               {

                    //      一次获取其中每一个ServiceDecriptor然后创建对应的ServiceCallSite

                    var descriptor = descriptors[i];

                    //  设置当前slot

                    //   slot为倒序设置

                    var slot = descriptors.Count - i - 1;

                    // There may not be any open generics here

                    //      获取当前ServiceDecriptor的ServiceCallSite并添加数组中

                    var callSite = TryCreateExact(descriptor, itemType, callSiteChain, slot);

                    callSites.Add(callSite);

               }

          }

          else

          {

               var 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;

}
代码语言:txt
复制
在`CallSiteFactory`类中还具有一个\*\*Add()\*\*,这个方法是往\*\*\_callSiteCache\*\*字段添加缓存`ServiceCallSite`
代码语言:txt
复制
 public void Add(Type type, ServiceCallSite serviceCallSite)

      => \_callSiteCache[type] = serviceCallSite;

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • ServiceCallSite
    • ServiceCallSite
      • ServiceCallSite
        • ConstantCallSite
          • ConstructorCallSite
            • IEnumerableCallSite
              • ServiceScopeFactoryCallSite
                • 1.TryCreateExact()
                • 2.TryCreateOpenGeneric()
                • 3.TryCreateEnumerable()
            • ServiceDescriptorCacheItem
            • CallSiteFactory
            相关产品与服务
            容器服务
            腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档