Core官方DI解析(3)-ServiceCallSite.md

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

ServiceCallSite

ServiceCallSite

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

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

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类型

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类中会注册此类实例,然后获取子类容器使用

?

? 这六个派生类中ConstantCallSiteIEnumerableCallSiteServiceProviderCallSiteServiceScopeFactoryCallSite这四个类的ResultCache属性使用的是None,而ConstructorCallSiteFactoryCallSiteResultCache属性则由构造器传入,具体则有其服务注册的生命周期进行实例化ResultCache

?

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

ConstantCallSite

? 既然ConstantCallSite是具体实例注册的,所以此类中具有一个实例对象属性,由下面代码可以看出在构造此类实例时传入实例值,然后赋值给DefaultValue属性,这个类型也是这些派生类中唯一一个拥有具体实例的,

? 然后Kind这个属性可以看到被赋值成了CallSiteKind.Constant,前面说过这个属性相当于代表此类型的属性,其它派生类都具有相应的枚举值

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

? 这个类中具有两个主要属性

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

ParameterCallSites:构造参数数组

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

?

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

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

?

? 这个类型是子容器的工厂类型,下面代码中看到ImplementationType是一个ServiceProviderEngine类型,其实这个引擎类不止实现了IServiceProviderEngine接口,还实现了IServiceScopeFactory

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

?

? 从下面代码可以看出这是一个结构,这个结构是具有相同注册服务的所有ServiceDescriptor封装,在CallSiteFactory类中进行使用

 private struct ServiceDescriptorCacheItem{}

? 在此结构中,可以看到具有两个字段**_item属性和一个_items集合属性,_item属性代表相同注册服务的第一个ServiceDescriptor,而_items**则是除去第一个其它的ServiceDescriptor集合,我没看懂微软为什么要这么干

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

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

?

? 此结构中的LastCount分别是获取缓存的最后一个元素和数量,因为第一个ServiceDescriptor是**_item属性,所以这两个属性都考虑了_item**,

/// <summary>
///     获取其注册的最后一个ServiceDescriptor
///     如果其_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];
     }
}

? 结构中只有一个And()方法,此方法是添加一个ServiceDescriptor,可以每次调用此方法时都会创建新的实例,

//     将指定固定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

? 下面来看看CallSiteFactory这个类型,这是ServiceCallSite的工厂类型,内部根据ServiceDescriptor创建对应的ServiceCallSite,下面一点点来看看这个类型

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

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

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

_callSiteCache:ServiceCallSite的缓存集合

_descriptorLookup:ServiceDescriptorCacheItem缓存集合

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

?

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

public CallSiteFactory(IEnumerable<ServiceDescriptor> descriptors)
{
     _stackGuard = new StackGuard();
     _descriptors = descriptors.ToList();
     //      调用此方法缓存ServiceDescriptorCacheItem
     Populate(descriptors);
}

? 在Populate方法中,首先经过了一系列的判断,最进行缓存

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是一个存放了所有相同注册基类的ServiceDescriptor
          //      ServiceDescriptorCacheItem中具有一个item属性和一个items集合
          //      item属性是注册的第一个此类型的ServiceDescriptor
          var cacheKey = descriptor.ServiceType;
          //        由于ServiceDescriptorCacheItem是一个结构,所以不会异常
          _descriptorLookup.TryGetValue(cacheKey, out var cacheItem);
          _descriptorLookup[cacheKey] = cacheItem.Add(descriptor);
     }
}

? 在此类中具有一个GetCallSite()方法,外部也是调用此方法进行获取ServiceCallSite,如果当前ServiceCallSite已被缓存,则直接获取缓存中数据,如果未缓存,则创建并缓存,从下面代码可以看到,如果未被缓存就调用CreateCallSite()进行创建

? 当前函数中有一个CallSiteChain类型,这个类型是一个限制,应该是为了防止多线程,在创建之前进行了判断,如果已创建,则抛出异常,CallSiteChain这个类在此就不做介绍

internal ServiceCallSite GetCallSite(Type serviceType, CallSiteChain callSiteChain)
     => _callSiteCache.GetOrAdd(serviceType, (type, chain) => CreateCallSite(type, chain), callSiteChain);

? 在CreateCallSite()首先调用了CallSiteChain实例的CheckCircularDependency()方法,这个方法就是如果已被创建,则抛出异常.然后分别调用TryCreateExact(),TryCreateOpenGeneric(),TryCreateEnumerable()这三个方法进行尝试实例化ServiceCallSite,下面我们来看看这三个方法和它们依赖的方法

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

? TryCreateExact()方法是如果ServiceType只是一个普通类型时才使用的方法,如下代码,首先判断了此类型是否存在于**_descriptorLookup缓存中,如果不存在直接返回null,如果存在的话直接使用最后一个ServiceDescriptorDefaultSlot**进行,这也就是为什么总是会获取最后一个服务实例的原因

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

? TryCreateExact()中则根据注册服务的方式进行实例化ServiceCallSite可以看到使用具体实例对象和工厂时直接实例化ServiceCallSite,而使用类型注册时则又调用CreateConstructorCallSite()进行实例化一个ConstructorCallSite对象

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

? 下面看一下CreateConstructorCallSite()这个方法,在这个方法中选择最优构造器并实例化ConstructorCallSite对象,

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

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

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

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

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

? 在此方法中如果最优构造器拥有参数,还会调用一个CreateArgumentCallSites(),这个方法会依次实例化参数的ServiceCallSite

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

? 在CreateArgumentCallSites()中递归调用GetCallSite()获取每一个参数对应的ServiceCallSite,在方法中可以看到如果从GetCallSite()中未获取到对应的实例对象但是该参数具有默认参数,那么就使用默认参数.

? 在这个方法有意思的是最后一个参数,最后一个参数如果为true,那么如果最终未获取到参数的ServiceCallSite就抛出一场,如果为false,就返回null

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

? 从下面代码可以看出TryCreateOpenGeneric()首先会判断此泛型是否是封闭类型并且此类型是否存在于**_descriptorLookup,然后调用TryCreateOpenGeneric()**进行获取ServiceCallSite

? 在TryCreateOpenGeneric()中则根据注册服务类型的泛型参数制造一个实现类型参数,然后调用CreateConstructorCallSite()进行实例化ServiceCallSite,所以泛型只能以构造器实例方式

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

? 最后我们来看看TryCreateEnumerable()这个方法,这个方法就是获取IEnumerableCallSite类型的,也就是获取当前注册类型所有实例时使用的,从下面代码可以看到如果IEnumerable的泛型参数不是泛型并且缓存于**_descriptorLookup集合中,就使用对应的所有的ServiceProvider进行实例化,如果二者有一不可就遍历_descriptors**实例ServiceCallSite

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

? 在CallSiteFactory类中还具有一个Add(),这个方法是往**_callSiteCache**字段添加缓存ServiceCallSite

 public void Add(Type type, ServiceCallSite serviceCallSite)
      => _callSiteCache[type] = serviceCallSite;

原文地址:https://www.cnblogs.com/yan7/p/10030080.html

时间: 2024-10-10 06:18:56

Core官方DI解析(3)-ServiceCallSite.md的相关文章

Core官方DI解析(4)--CallSiteRuntimeResolver

? CallSiteRuntimeResolver类型是一个创建或获取服务实例的类型,这个类型继承了CallSiteVisitor<TArgument, TResult>这个类型,也是使用了访问者模式,下面一一来解析此类 ServiceProviderEngineScope 在解析`CallSiteRuntimeResolver`之前先看一下`ServiceProviderEngineScope`类型,这个类型就可以是一个容器类型,最后实例化的服务对象就缓存在此类之中, 从下面代码中可以看出此

ASPNET CORE 的 DI 依赖注入 及 AuotoFac 的引入

学习有关Aspnet Core 的DI及IOC等,参考: 1.全面理解 ASP.NET Core 依赖注入    https://blog.csdn.net/hiliqi/article/details/80611209 提及 AuotoFac 的引入Aspnet Core的方式: 把Startup类里面的 ConfigureService的 返回值从 void改为 IServiceProvider即可. public IServiceProvider ConfigureServices(   

Android应用之——谷歌官方Json解析工具Gson的使用

一.Gson简介 Gson(又称Google Gson)是Google公司发布的一个开放源代码的Java库,主要用途为串行化Java对象为JSON字符串,或反串行化JSON字符串成Java对象.也就是Java对象与json字符串间的互相转换,解析. 二.使用方法 Gson的应用主要为toJson与fromJson两个转换函数,而在使用这种对象转换之前需先创建好对象的类型以及其成员才能成功的将JSON字符串成功转换成相对应的对象.即先创建好对应的javabean,javabean中的字段与要转换的

Android实例-Delphi开发蓝牙官方实例解析(XE10+小米2+小米5)

Android实例-Delphi开发蓝牙官方实例解析(XE10+小米2+小米5) 相关资料:1.http://blog.csdn.net/laorenshen/article/details/411498032.http://www.cnblogs.com/findumars/p/5149128.html 一.理清概念1.蓝牙设备:是指代有蓝牙通信的手机.电脑.平板.打印机.耳机等.2.设备名称:是指设备打开蓝牙功能后,在其他设备中显示的名字,如图1用的A.B.C等.3.蓝牙关态:如果A手机没有

实战Asp.Net Core:DI生命周期

原文:实战Asp.Net Core:DI生命周期 title: 实战Asp.Net Core:DI生命周期 date: 2018-11-30 21:54:52 --- 1.前言 Asp.Net Core 默认支持 DI(依赖注入) 软件设计模式,那使用 DI 的过程中,我们势必会接触到对象的生命周期,那么几种不同的对象生命周期到底是怎么样的呢?我们拿代码说话. 关于 DI 与 IOC: 个人理解:IOC(控制反转) 是目的(降低代码.服务间的耦合),而 DI 是达到该目的的一种手段(具体办法).

ASP.NET Core官方计划路线及需要废除的一些Framework技术

概述 下面是 ASP.NET Core的时间表和路线图. 注意日期和特性都可能更改. 作为.NET Core这么大的一个项目,很难准确预测每一个计划的是否有变动. 即便如此,我们还是计划公开和透明的实施,以便我们的用户可以有正确的期望值, 并为我们的用户自己在技术实施时有更好的打算和安排 发布时间表 Release 发布日志 1.1 Q4 2016 / Q1 2017 1.2 Q1 2017 / Q2 2017 Release 版本特性 1.1 URL 重写中间件 Response 缓存中间件

Android开源库--Gson谷歌官方json解析库

官方文档地址:http://google-gson.googlecode.com/svn/trunk/gson/docs/javadocs/index.html 官方网站:http://code.google.com/p/google-gson/ json官方网站:http://www.json.org/json-zh.html 目前主流数据传输都用的是json,解析json并且转换成相应的类型就成了必经之路. 在没有使用gson之前,原生Andoird自带有类解析json,但是实在不方便使用.

.NET Core HtmlAgilityPack HTML解析利器

最近学习.NET Core ,想把自己之前的一个项目升级到 .NET Core. 发现HtmlAgilityPack 没法进行引用,遂自己做了些修改,可以运行在 .NET Core 中.现在分享出来,也是为  .NET Core 做一些贡献. .NET Core版 HtmlAgilityPack HTML解析利器,目前是 HtmlAgilityPack Core RC2 HtmlAgilityPack 介绍 HtmlAgilityPack是一个基于.Net的.第三方免费开源的微型类库,主要用于在

ActivityLifeCycle官方demo解析

1.关于Activity的生命周期的几篇文章: http://1.duoinfo.sinaapp.com/?p=330 http://1.duoinfo.sinaapp.com/?p=332 http://1.duoinfo.sinaapp.com/?p=335 http://1.duoinfo.sinaapp.com/?p=337 training课程给的图是这样的: 2.运行官方的程序 看到这个demo含有四个Activity,最后一个Activity的样式文件为dialog.并且在下面用T