Core官方DI解析-ServiceCallSite.md
Posted yan7
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Core官方DI解析-ServiceCallSite.md相关的知识,希望对你有一定的参考价值。
上一篇说过在整个DI框架中IServiceProviderEngine
是核心,但是如果直接看IServiceProviderEngine
派生类其实看不出也没什么东西,因为这个类型其实都是调用的其它对象方法,所以我们先来看看其它的类型
ServiceCallSite
ServiceCallSite
? 这个是一个服务访问配置的类型,DI内部使用此类的派生类型进行封装所需要实例化的信息然后进行实例化服务对象,首先我们先来看一下ServiceCallSite
这个类所拥有的属性。从下面可以看到ServiceCallSite
具有三个抽象属性和一个非抽象属性,其中ServiceType和ImplementationType已经知道代表注册的服务类型和实例对象的类型,
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类中会注册此类实例,然后获取子类容器使用
?
? 这六个派生类中ConstantCallSite
,IEnumerableCallSite
,ServiceProviderCallSite
和ServiceScopeFactoryCallSite
这四个类的ResultCache属性使用的是None,而ConstructorCallSite
和FactoryCallSite
的ResultCache属性则由构造器传入,具体则有其服务注册的生命周期进行实例化ResultCache
?
] 在这里看一下ConstantCallSite
,ConstructorCallSite
,IEnumerableCallSite
和ServiceScopeFactoryCallSite
这四个类
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
集合
?
? 此结构中的Last和Count分别是获取缓存的最后一个元素和数量,因为第一个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,如果存在的话直接使用最后一个ServiceDescriptor和DefaultSlot**进行,这也就是为什么总是会获取最后一个服务实例的原因
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;
以上是关于Core官方DI解析-ServiceCallSite.md的主要内容,如果未能解决你的问题,请参考以下文章