上一篇说过在整个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,而ConstructorCallSiteFactoryCallSite ResultCache属性则由构造器传入,具体则有其服务注册的生命周期进行实例化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;

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

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

    ​ CallSiteRuntimeResolver类型是一个创建或获取服务实例的类型,这个类型继承了CallSiteVisitor<TArgument, TResult>这个类型,也是使用 ...

  2. Core官方DI解析(2)-ServiceProvider

    ServiceProvider ServiceProvider是我们用来获取服务实例对象的类型,它也是一个特别简单的类型,因为这个类型本身并没有做什么,其实以一种代理模式,其核心功能全部都在IServ ...

  3. Core官方DI解析(5)-ServiceProviderEngine

    最后来看看前面一直说的Engine(工作引擎),工作引擎接口是IServiceProviderEngine在ServiceProvider的构造函数中看到了根据指定的Mode创建了不同的实现类,下面先 ...

  4. Core官方DI剖析(1)--ServiceProvider类和ServiceCollection类

    前段时间看了蒋老师的Core文章,对于DI那一块感觉挺有意思,然后就看了一下Core官方DI的源码,这也算是第一个看得懂大部分源码的框架,虽然官方DI相对来说特别简单, 官方DI相对于其它框架(例如 ...

  5. abp vnext2.0核心组件之.Net Core默认DI组件切换到AutoFac源码解析

    老版Abp对Castle的严重依赖在vnext中已经得到了解决,vnext中DI容器可以任意更换,为了实现这个功能,底层架构相较于老版abp,可以说是进行了高度重构.当然这得益于.Net Core的D ...

  6. Asp.Net Core中DI的知识总结

    在asp.net core中DI的概念是由这几部分组成的: IServiceCollection,保存IServiceDescriptor实例的列表 IServiceProvider,只有一个方法Ge ...

  7. asp.net core的DI框架思考以及服务实例的获取方式总结

    转载请注明出处: https://home.cnblogs.com/u/zhiyong-ITNote/ 整个asp.net core管道从WebHostBuilder到WebHost到后续请求的类中, ...

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

    title: 实战Asp.Net Core:DI生命周期 date: 2018-11-30 21:54:52 --- 1.前言 Asp.Net Core 默认支持 DI(依赖注入) 软件设计模式,那使 ...

  9. 阅读DMA Controller Core 官方手册

    阅读DMA Controller Core 官方手册 DMA控制器框架图 怎样去设定一个DMA控制器 实例化DMA控制器 参数配置界面如下图所示: 对于width of the DMA length ...

随机推荐

  1. 两篇文章带你走入.NET Core 世界:CentOS+Kestrel+Ngnix 虚拟机先走一遍(一)

    背景: 上一篇:ASP.Net Core on Linux (CentOS7)共享第三方依赖库部署 已经交待了背景,这篇就省下背景了. 折腾的过程分两步: 第一步是:本机跑虚拟机部署试一下: 第二步是 ...

  2. WebDeploy to remote IIS

        参考 Web Platform Installer Direct Downloads

  3. 从壹开始前后端分离【 .NET Core2.0 +Vue2.0 】框架之二 || 后端项目搭建

    前言 至于为什么要搭建.Net Core 平台,这个网上的解释以及铺天盖地,想了想,还是感觉重要的一点,跨平台,嗯!没错,而且比.Net 更容易搭建,速度也更快,所有的包均有Nuget提供,不再像以前 ...

  4. Asp.Net Core 轻松学-被低估的过滤器

    前言     过滤器,从我们开始开发 Asp.Net 应用程序开始,就一直伴随在我们左右:Asp.Net Core 提供多种类型的过滤器,以满足多种多样的业务应用场景:并且在 Asp.Net Core ...

  5. Centos7+LVS-DR+Apache负载均衡web实验

    一.简介 1.理论已经在上一篇博客简述,不了解得可以看看 https://www.cnblogs.com/zhangxingeng/p/10497279.html 2.LVS-DR优缺点复习 关于这种 ...

  6. 关于C#的new与override

    先放出来两个基类和派生类: public class BaseClass { public virtual void Method1(string desc) { Console.WriteLine( ...

  7. docker daemon 配置文件

    Ubuntu Ubuntu 14.04 配置文件位于 /etc/init/docker.conf Ubuntu 15.04 配置文件位于 /etc/default/docker,修改配置项DOCKER ...

  8. 简述ADO.NET的连接层

    前面曾提到过ADO.NET的连接层允许通过数据提供程序的连接.命令.数据读取器对象与数据库进行交互.当想连接数据库并且使用一个数据读取器对象来读取数据时.需要实现下面的几个步骤 * 创建.配置.打开连 ...

  9. 学JAVA第十八天,接口与抽象类进一步加深

    昨天老师讲了建网站,还要交钱买东西的,所以就没写,今天讲了接口与抽象类进一步加深 上完今天的课后,我才知道一个接口可以有多个实现类,一个实现类可以同时接多个接口. 现在就用代码来解释吧!!! 举例用人 ...

  10. 80后程序员降薪6K,预感中年危机来袭,准备跳槽却碰壁

    一提及程序员,很多人想到的都是“工资高”“技术好”诸如此类的,可见程序员是个非常赚钱的职业,所以每年都会有很多毕业生来选择这个行业. 但是社会是公平的,不要只看程序员表面上的光鲜亮丽,其背后也有很多的 ...