ASP.NET CORE 默认DI默认实现包分析(DependencyInjectionAbstractions,c#,asp.net,.net,IOC)

DependencyInjection概述

ServiceIdentifier

internal readonly struct ServiceIdentifier : IEquatable<ServiceIdentifier> {
    // service的key标识
		public object? ServiceKey { get; }
		// service的类型
    public Type ServiceType { get; }
  	//创建 携带key标识的service的身份证
  	public static ServiceIdentifier FromDescriptor(ServiceDescriptor serviceDescriptor)
            => new ServiceIdentifier(serviceDescriptor.ServiceKey, serviceDescriptor.ServiceType);
    //创建 不ey标识的service的身份证
    public static ServiceIdentifier FromServiceType(Type type) => new ServiceIdentifier(null, type);

		public ServiceIdentifier(Type serviceType){
         ServiceType = serviceType;
    }
		public ServiceIdentifier(object? serviceKey, Type serviceType){
         ServiceKey = serviceKey; ServiceType = serviceType;
    }
		public ServiceIdentifier GetGenericTypeDefinition() => new ServiceIdentifier(ServiceKey, ServiceType.GetGenericTypeDefinition());
}

服务身份证:身份证构成 serviceKey(key标识) + serviceType

ServiceDescriptorCacheItem

 private struct ServiceDescriptorCacheItem{
 	 //这里存储的是 同一个ServiceIdentifier的多个实现时,第一个注册进来的值
   private ServiceDescriptor? _item;
   //存储 同一个ServiceIdentifier的多个实现,并添加到一起,而他们的顺序就是他们在ServiceCacheKey中的slot(槽位)
   private List<ServiceDescriptor>? _items;
   public ServiceDescriptor Last{
           get{
                if (_items != null && _items.Count > 0){
                      return _items[_items.Count - 1];
                }
              return _item;
            }
  }

   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];
          }
   }
   
   public int GetSlot(ServiceDescriptor descriptor)
   {
     if (descriptor == _item){
       return Count - 1;
     }
     if (_items != null){
       int index = _items.IndexOf(descriptor);
       if (index != -1){
         return _items.Count - (index + 1);
       }
     }
     throw new InvalidOperationException(SR.ServiceDescriptorNotExist);
   }
   
   public ServiceDescriptorCacheItem Add(ServiceDescriptor descriptor){
     var newCacheItem = default(ServiceDescriptorCacheItem);
     if (_item == null){
       newCacheItem._item = descriptor;
     }
     else{
       newCacheItem._item = _item;
       newCacheItem._items = _items ?? new List<ServiceDescriptor>();
       newCacheItem._items.Add(descriptor);
     }
     return newCacheItem;
   }
 }
}

通过 ServiceDescriptor 中的 ServiceKey 和 ServiceType 去创建出 ServiceIdentifier,再根据ServiceIdentifier是否相同,将相同的ServiceIdentifier的ServiceDescriptor存放在ServiceDescriptorCacheItem中的list集合中,而list集合中的存放顺序实际上就是 ServiceCacheKey上对应的槽位。

ServiceCacheKey

internal readonly struct ServiceCacheKey : IEquatable<ServiceCacheKey> {
       
        public ServiceIdentifier ServiceIdentifier { get; }
        /// 对于同一个 ServiceIdentifier 中有多个实现类
        /// For example for service collection
        ///  IService Impl1
        ///  IService Impl2
        ///  IService Impl3
        /// We would get the following cache keys:
        ///  Impl1 2
        ///  Impl2 1
        ///  Impl3 0
        /// </summary>
        public int Slot { get; }

        public ServiceCacheKey(object key, Type type, int slot){
            ServiceIdentifier = new ServiceIdentifier(key, type);
            Slot = slot;
        }
        public ServiceCacheKey(ServiceIdentifier type, int slot){
            ServiceIdentifier = type;
            Slot = slot;
        }
}

小结

ServiceIdentifier = ServiceDescriptor.serviceKey + ServiceDescriptor.serviceType

ServiceCacheKey = ServiceIdentifier + slot( List.index位置)

ServiceDescriptorCacheItem = List + List[0]

ServiceCallSite(服务调用站点)

internal abstract class ServiceCallSite{
  protected ServiceCallSite(ResultCache cache){
    Cache = cache;
  }
  //服务的类型
  public abstract Type ServiceType { get; }
  //服务的实现可续
  public abstract Type? ImplementationType { get; }
  //调用站点类型
  public abstract CallSiteKind Kind { get; }
  //服务的生命周期,serviceIdentifier(服务身份证)以及服务所在ServiceDescriptorCacheItem-list的位置
  public ResultCache Cache { get; }
  //单例储存的地方
  public object? Value { get; set; }
  public object? Key { get; set; }
}

ConstantCallSite

CallSiteFacory.TryCreateExact方法中可知:

if (descriptor.HasImplementationInstance()){
callSite = new ConstantCallSite(descriptor.ServiceType, descriptor.GetImplementationInstance());
}
//descriptor.HasImplementationInstance()方法最终来到此进行判断,就是判断是否以及存在service的实例
public static object? GetImplementationInstance(this ServiceDescriptor serviceDescriptor)
{
 return serviceDescriptor.IsKeyedService
     ? serviceDescriptor.KeyedImplementationInstance
     : serviceDescriptor.ImplementationInstance;
}
  • 由上可知:
  • ConstantCallSite应用与 serviceDescription 中_implementationInstance不为空的情况
  • 而_implementationInstance不为空的话,说明该服务调用站点的生命周期为单例,因为在构建服务的时候如果传了服务类型对应的实例对象的话,则为单例,在DependencyInjection.Abstractions可得

ConstructorCallSite

CallSiteFacory.TryCreateExact方法中可知:

else if (descriptor.HasImplementationType()){
callSite = CreateConstructorCallSite(lifetime, serviceIdentifier, descriptor.GetImplementationType()!, callSiteChain);
}
public static Type? GetImplementationType(this ServiceDescriptor serviceDescriptor){
return serviceDescriptor.IsKeyedService
? serviceDescriptor.KeyedImplementationType
: serviceDescriptor.ImplementationType;
}
  • 由上可知:
  • ConstructorCallSite 应用与 serviceDescription 中 _implementationType不为空的情况

FactoryCallSite

CallSiteFacory.TryCreateExact方法中可知:

else if (!descriptor.IsKeyedService && descriptor.ImplementationFactory != null){
callSite = new FactoryCallSite(lifetime, descriptor.ServiceType, descriptor.ImplementationFactory);
}
else if (descriptor.IsKeyedService && descriptor.KeyedImplementationFactory != null){
callSite = new FactoryCallSite(lifetime, descriptor.ServiceType, serviceIdentifier.ServiceKey!, descriptor.KeyedImplementationFactory);
}
  • 由上可知:
  • FactoryCallSite 应用与 serviceDescription 中 _implementationFactory 不为空的情况

IEnumerableCallSite

CallSiteFacory.CreateCallSite方法中可知:

private ServiceCallSite? CreateCallSite(ServiceIdentifier serviceIdentifier, CallSiteChain callSiteChain){

var callsiteLock = _callSiteLocks.GetOrAdd(serviceIdentifier, static _ => new object());
		lock (callsiteLock){
callSiteChain.CheckCircularDependency(serviceIdentifier);
ServiceCallSite? callSite = TryCreateExact(serviceIdentifier, callSiteChain) 
  ?? TryCreateOpenGeneric(serviceIdentifier, callSiteChain) 
  ??TryCreateEnumerable(serviceIdentifier, callSiteChain);
eturn callSite;
}
}

TryCreateExact 是尝试匹配准确类型,TryCreateOpenGeneric 是尝试匹配泛型类型,TryCreateEnumerable则是尝试匹配IEnumerable类型。

当 serviceProvider.getservice<IEnumerable>() 或serviceProvider.getservice(IEnumerable)时,再TryCreateExact和TryCreateOpenGeneric中会无法匹配上,从而执行到TryCreateEnumerable,去创建IEnumerable的调用站点。

CallSiteFactory(服务调用站点总站)

internal sealed class CallSiteFactory : IServiceProviderIsService, IServiceProviderIsKeyedService{
        private const int DefaultSlot = 0;
  			//存储了serviceCollection中所有的ServiceDescriptor
        private readonly ServiceDescriptor[] _descriptors;
  			//缓存了 ServiceIdentifier 对应ServiceDescriptorCacheItem的Items中Item的服务调用节点
        private readonly ConcurrentDictionary<ServiceCacheKey, ServiceCallSite> _callSiteCache = new ConcurrentDictionary<ServiceCacheKey, ServiceCallSite>();
    	//缓存了 ServiceIdentifier对应的ServiceDescriptorCacheItem
        private readonly Dictionary<ServiceIdentifier, ServiceDescriptorCacheItem> _descriptorLookup = new Dictionary<ServiceIdentifier, ServiceDescriptorCacheItem>();
  		//缓存了ServiceIdentifier的对象锁
        private readonly ConcurrentDictionary<ServiceIdentifier, object> _callSiteLocks = new ConcurrentDictionary<ServiceIdentifier, object>();
			//栈守卫
        private readonly StackGuard _stackGuard;
}
  • 负责创建和缓存所有的ServiceCallSite
  • 存储了serviceCollection中所有的ServiceDescriptor
  • 对ServiceDescriptor进行了分类,serviceKey以及serviceType相同的ServiceDescriptor的会被归在同一个类链条上(实际上也不算是链条)
  • 缓存了所有 ServiceIdentifier + solt 对应的 服务调用站点

ServiceProvider

public sealed class ServiceProvider : IServiceProvider, IKeyedServiceProvider, IDisposable, IAsyncDisposable{
   //服务获取站点校验器
   private readonly CallSiteValidator? _callSiteValidator;
   // 创建ServiceAccessor(服务访问者)的委托
	 private readonly Func<ServiceIdentifier, ServiceAccessor> _createServiceAccessor;
   //创建ServiceAccessor(服务访问者)引擎
   internal ServiceProviderEngine _engine;
  // 存储对应ServiceIdentifier对应的ServiceAccessor(服务访问者)
   private readonly ConcurrentDictionary<ServiceIdentifier, ServiceAccessor> _serviceAccessors;
  //用于创建和缓存服务的调用站点
   internal CallSiteFactory CallSiteFactory { get; }
  //用于 root 的生命周期管理
   internal ServiceProviderEngineScope Root { get; }
}

DefaultServiceProviderFactory

DefaultServiceProviderFactory是IServiceProviderFactory的默认实现类

public class DefaultServiceProviderFactory : IServiceProviderFactory<IServiceCollection>{
private readonly ServiceProviderOptions _options;
public DefaultServiceProviderFactory() : this(ServiceProviderOptions.Default){
}
public DefaultServiceProviderFactory(ServiceProviderOptions options){
_options = options ?? throw new ArgumentNullException(nameof(options));
}
public IServiceCollection CreateBuilder(IServiceCollection services){
return services;
}
public IServiceProvider CreateServiceProvider(IServiceCollection containerBuilder){
return containerBuilder.BuildServiceProvider(_options);
}
}

ServiceProviderEngineScope

  • ServiceProviderEngineScope为ServiceProvider提供作用域的能力
  • scope服务的生命周期的存储位置
internal sealed class ServiceProviderEngineScope : 
IServiceScope, 
IServiceProvider, 
IKeyedServiceProvider, 
IAsyncDisposable, 
IServiceScopeFactory{
internal IList<object> Disposables => _disposables ?? (IList<object>)Array.Empty<object>();
//是否进行了释放
private bool _disposed;
//scope生命周期的服务 和 实现了IDisposable接口的瞬时生命周期服务 都会被加入到此处,便于释放对象
	private List<object>? _disposables;
public ServiceProviderEngineScope(ServiceProvider provider, bool isRootScope){
  ResolvedServices = new Dictionary<ServiceCacheKey, object?>();
  RootProvider = provider;
  IsRootScope = isRootScope;
}
//scope生命周期服务的内存存储位置
internal Dictionary<ServiceCacheKey, object?> ResolvedServices { get; }
//是否是root作用域
public bool IsRootScope { get; }
//不管是root作用域,还是非root作用,在同一个serviceProvider下创建的作用域,都是同一个ServiceProvider
internal ServiceProvider RootProvider { get; }
//创建非root作用域
public IServiceScope CreateScope() => RootProvider.CreateScope();
}

ServiceProviderEngine

internal abstract class ServiceProviderEngine{
  public abstract Func<ServiceProviderEngineScope, object?> RealizeService(ServiceCallSite callSite);
}
}
  • 这个类的职责就是创建服务【传入作用域,解析服务】。
  • 也是吧服务作用域与服务调用站点进行了解耦

DynamicServiceProviderEngine

internal sealed class DynamicServiceProviderEngine : CompiledServiceProviderEngine{
private readonly ServiceProvider _serviceProvider;
public DynamicServiceProviderEngine(ServiceProvider serviceProvider) : base(serviceProvider){
_serviceProvider = serviceProvider;
}
public override Func<ServiceProviderEngineScope, object?> RealizeService(ServiceCallSite callSite){
int callCount = 0;
return scope =>{
//返回真正创建对应服务的委托方法
var result = CallSiteRuntimeResolver.Instance.Resolve(callSite, scope);
if (Interlocked.Increment(ref callCount) == 2){
  _ = ThreadPool.UnsafeQueueUserWorkItem(_ =>{
    try{
      //如果当前是第二次调用,则调用父级进行缓存
      _serviceProvider.ReplaceServiceAccessor(callSite, base.RealizeService(callSite));
    }
    catch (Exception ex){
     //.......
    }
  },null);
}
return result;
};
}
}

DynamicServiceProviderEngine就是把真正创建服务的方法进行了一层包装,生成委托方法,并且启用线程

CallSiteVisitor

  • 服务调用站点访客,从这个类作为中转类。
  • 转到Root,scope,顺序作用域去做服务的缓存操作
  • 转到构建对应服务的ServiceCallSite
internal abstract class CallSiteVisitor<TArgument, TResult>{

protected virtual TResult VisitCallSite(ServiceCallSite callSite, TArgument argument){
		//...
  switch (callSite.Cache.Location){
    case CallSiteResultCacheLocation.Root:
      return VisitRootCache(callSite, argument);
    case CallSiteResultCacheLocation.Scope:
      return VisitScopeCache(callSite, argument);
    case CallSiteResultCacheLocation.Dispose:
      return VisitDisposeCache(callSite, argument);
    case CallSiteResultCacheLocation.None:
      return VisitNoCache(callSite, argument);
    default:
      throw new ArgumentOutOfRangeException();
  }
}
protected virtual TResult VisitCallSiteMain(ServiceCallSite callSite, TArgument argument){
  switch (callSite.Kind)
  {
    case CallSiteKind.Factory:
      return VisitFactory((FactoryCallSite)callSite, argument);
    case CallSiteKind.IEnumerable:
      return VisitIEnumerable((IEnumerableCallSite)callSite, argument);
    case CallSiteKind.Constructor:
      return VisitConstructor((ConstructorCallSite)callSite, argument);
    case CallSiteKind.Constant:
      return VisitConstant((ConstantCallSite)callSite, argument);
    case CallSiteKind.ServiceProvider:
      return VisitServiceProvider((ServiceProviderCallSite)callSite, argument);
    default:
      throw new NotSupportedException(SR.Format(SR.CallSiteTypeNotSupported, callSite.GetType()));
  }
}



protected virtual TResult VisitNoCache(ServiceCallSite callSite, TArgument argument){
  return VisitCallSiteMain(callSite, argument);
}
protected virtual TResult VisitDisposeCache(ServiceCallSite callSite, TArgument argument){
  return VisitCallSiteMain(callSite, argument);
}
protected virtual TResult VisitRootCache(ServiceCallSite callSite, TArgument argument){
  return VisitCallSiteMain(callSite, argument);
}
protected virtual TResult VisitScopeCache(ServiceCallSite callSite, TArgument argument){
  return VisitCallSiteMain(callSite, argument);
}


protected abstract TResult VisitConstructor(ConstructorCallSite constructorCallSite, TArgument argument);
protected abstract TResult VisitConstant(ConstantCallSite constantCallSite, TArgument argument);
protected abstract TResult VisitServiceProvider(ServiceProviderCallSite serviceProviderCallSite, 
                                                TArgument argument);
protected abstract TResult VisitIEnumerable(IEnumerableCallSite enumerableCallSite, TArgument argument);
protected abstract TResult VisitFactory(FactoryCallSite factoryCallSite, TArgument argument);

}

CallSiteRuntimeResolver

CallSiteRuntimeResolver是CallSiteVisitor的默认实现:主要是实现了不同的生命周期的服务,存储到对应生命周期的位置。

Q&A

(1)如何解决非Root作用域释放导致单例生命周期对象中引入的非Root作用域的Scope生命周期对象释放问题?

public static void Main(string[] args){
IServiceCollection services = new ServiceCollection();
services.AddSingleton<DemoTwo>();
services.AddScoped<DemoOne>(provider => new() { Id = 1, Name = "binbinbin", Sex = "man" });
IServiceProvider serviceProvider = services.BuildServiceProvider();
DemoTwo demoTwo = null;

using (IServiceScope serviceScope = serviceProvider.CreateScope()){
demoTwo = serviceScope.ServiceProvider.GetService<DemoTwo>();
Console.WriteLine("not RootScope DemoTwo Hashcode:" + demoTwo.GetHashCode());
Console.WriteLine("not RootScope DemoTwo GetDemoOne" + demoTwo.GetDemoOne());
}

demoTwo = serviceProvider.GetService<DemoTwo>();
Console.WriteLine("RootScope DemoTwo Hashcode:" + demoTwo.GetHashCode());
Console.WriteLine("RootScope DemoTwo GetDemoOne" + demoTwo.GetDemoOne());

using (IServiceScope serviceScope = serviceProvider.CreateScope()){
demoTwo = serviceScope.ServiceProvider.GetService<DemoTwo>();
Console.WriteLine("not RootScope DemoTwo Hashcode:" + demoTwo.GetHashCode());
Console.WriteLine("not RootScope DemoTwo GetDemoOne" + demoTwo.GetDemoOne());
}
public class DemoOne{
public int Id { get; set; }
public string Name { get; set; }
public string Sex { get; set; }
}

public class DemoTwo{
private readonly DemoOne _demoOne;
public DemoTwo(DemoOne demoOne){
  _demoOne = demoOne;
}
public string GetDemoOne(){
  return _demoOne.GetHashCode() + "";
}
}
}

先往serviceCollection中注册Scoped生命周期的DemoOne以及单例的DemoTwo,DemoTwo中依赖注入DemoOne

然后创建serviceProvider,注意创建serviceProvider,并不会创建DemoOne以及DemoTwo对应的ServiceCallSite以及他们的创建委托方法。但是注意的是,在另开了一个非root作用域(注意:DemoOne是scope作用域)里,GetService``DemoOne服务,但是DemoOne是单例的,但是DemoOne的注入参数是scope生命周期,那如果释放了该作用域,那单例再去使用该参数岂不是会有问题!,那默认di中是如何解决这个问题的:提升作用域。

从下代码可得:

protected override object? VisitScopeCache(ServiceCallSite callSite, RuntimeResolverContext context){
return context.Scope.IsRootScope ?
VisitRootCache(callSite, context)
:VisitCache(callSite, context, context.Scope, RuntimeResolverLock.Scope);
}

VisitScopeCache这里是对scope生命周期的服务进行缓存,如果这个服务是scope生命周期并且被依赖注入到单例的服务中,他的生命周期就会被提升。

(2)如何解决避免循环依赖的问题?

默认di中主要是依靠这条链子(CallSiteChain)去完成循环依赖的检测:

internal sealed class CallSiteChain{
private readonly Dictionary<ServiceIdentifier, ChainItemInfo> _callSiteChain;
public CallSiteChain(){
_callSiteChain = new Dictionary<ServiceIdentifier, ChainItemInfo>();
}
//.....
private readonly struct ChainItemInfo{
public int Order { get; }
public Type? ImplementationType { get; }
public ChainItemInfo(int order, Type? implementationType){
Order = order;
ImplementationType = implementationType;
}
}
}

循环依赖检测位置:

private ServiceCallSite? CreateCallSite(ServiceIdentifier serviceIdentifier, CallSiteChain callSiteChain){
if (!_stackGuard.TryEnterOnCurrentStack()){
return _stackGuard.RunOnEmptyStack(CreateCallSite, serviceIdentifier, callSiteChain);
}
      // We need to lock the resolution process for a single service type at a time:
      // Consider the following:
      // C -> D -> A
      // E -> D -> A
      // Resolving C and E in parallel means that they will be modifying the callsite cache concurrently
      // to add the entry for C and E, but the resolution of D and A is synchronized
      // to make sure C and E both reference the same instance of the callsite.

      // This is to make sure we can safely store singleton values on the callsites themselves
var callsiteLock = _callSiteLocks.GetOrAdd(serviceIdentifier, static _ => new object());
lock (callsiteLock){
//循环依赖检测
callSiteChain.CheckCircularDependency(serviceIdentifier);
ServiceCallSite? callSite = TryCreateExact(serviceIdentifier, callSiteChain) 
??TryCreateOpenGeneric(serviceIdentifier, callSiteChain) 
?? TryCreateEnumerable(serviceIdentifier, callSiteChain);
return callSite;
}
}

循环依赖添加:在TryCreateExactTryCreateOpenGenericTryCreateEnumerable方法中会有对应的循环依赖链条添加和检测

(3)关于GetService<IEnumerable<xxxx>>IEnumerable的生命周期

直接上源码,直接看到在哪构建IEnumerable的服务的地方,也就是TryCreateEnumerable#CallSiteFactory

//GetService调用情况一: GetService<IEnumerable<Demo>>
//GetService调用情况二: GetService<IEnumerable<ITest<Demo>>>
private ServiceCallSite? TryCreateEnumerable(
ServiceIdentifier serviceIdentifier, 
CallSiteChain callSiteChain){
//DefaultSlot默认等于0(传进来的会先是0),Slot有什么用?其实就是获取ServiceDescriptorCacheItem._items[Slot]
ServiceCacheKey callSiteKey = new ServiceCacheKey(serviceIdentifier, DefaultSlot);
//尝试获取缓存中的ServiceCallSite
if (_callSiteCache.TryGetValue(callSiteKey, out ServiceCallSite? serviceCallSite)){
return serviceCallSite;
}
try {
//处理循环依赖问题
callSiteChain.Add(serviceIdentifier);
//获取调用GetService中的泛型参数
var serviceType = serviceIdentifier.ServiceType;
		//判断调用GetService中的泛型参数的泛型定义是否是IEnumerable<>,
if (!serviceType.IsConstructedGenericType ||
  serviceType.GetGenericTypeDefinition() != typeof(IEnumerable<>)){
return null;
}
//获取IEnumerable<>中的第一个泛型参数
Type itemType = serviceType.GenericTypeArguments[0];
//创建他的ServiceIdentifier
var cacheKey = new ServiceIdentifier(serviceIdentifier.ServiceKey, itemType);

//....

CallSiteResultCacheLocation cacheLocation = CallSiteResultCacheLocation.Root;
ServiceCallSite[] callSites;

//判断调用GetService中的泛型参数的IEnumerable<>中的第一个泛型参数是否是 可构造的泛型类型
//什么是可构造的泛型类型,比如 ITest<DemoOne>,Test<DemoOne>就是可构造的泛型类型
//如果不是可构造的泛型类型,就进入if中,因为如果他不是可构造的泛型类型,说明可以直调用精确类型来构造就行
//并且拿出_descriptorLookup中对应储存的 cacheKey 的那条链条ServiceDescriptorCacheItem
if (!itemType.IsConstructedGenericType 
  && !KeyedService.AnyKey.Equals(cacheKey.ServiceKey) 
  &&  _descriptorLookup.TryGetValue(cacheKey, out ServiceDescriptorCacheItem descriptors)){
callSites = new ServiceCallSite[descriptors.Count];
for (int i = 0; i < descriptors.Count; i++){
  ServiceDescriptor descriptor = descriptors[i];
  //从链尾开始取对应的ServiceCallSite
  int slot = descriptors.Count - i - 1;
  //创建链条上对应注册服务的ServiceCallSite
  ServiceCallSite? callSite = TryCreateExact(descriptor, cacheKey, callSiteChain, slot);
  Debug.Assert(callSite != null);
  //比较每个ServiceCallSite的作用域,取最小的作用域
  //比如: 注册了DemoOne的两个类:DemoOne,DemoOne,DemoOne的生命周期是单例,DemoOne的生命周期是瞬时,那么IEnumerable<DemoOne>的生命周期就是瞬时
  cacheLocation = GetCommonCacheLocation(cacheLocation, callSite.Cache.Location);
  callSites[i] = callSite;
}
}
else{
List<KeyValuePair<int, ServiceCallSite>> callSitesByIndex = new();
int slot = 0;
for (int i = _descriptors.Length - 1; i >= 0; i--){
  //比较 _descriptors 中的ServiceKey和 调用GetService中的泛型参数的IEnumerable<>中的第一个泛型参数 是否相同
  if (KeysMatch(_descriptors[i].ServiceKey, cacheKey.ServiceKey)){
    if (TryCreateExact(_descriptors[i], cacheKey, callSiteChain, slot) is { } callSite){
      AddCallSite(callSite, i);
    }
  }
}
//
for (int i = _descriptors.Length - 1; i >= 0; i--){
   //比较 _descriptors 中的ServiceKey和 调用GetService中的泛型参数的IEnumerable<>中的第一个泛型参数 是否相同
  if (KeysMatch(_descriptors[i].ServiceKey, cacheKey.ServiceKey)){
    if (TryCreateOpenGeneric(
      _descriptors[i], 
      cacheKey, 
      callSiteChain, 
      slot, throwOnConstraintViolation: false) is { } callSite){
      AddCallSite(callSite, i);
    }
  }
}
callSitesByIndex.Sort((a, b) => a.Key.CompareTo(b.Key));
callSites = new ServiceCallSite[callSitesByIndex.Count];
for (var i = 0; i < callSites.Length; ++i){
  callSites[i] = callSitesByIndex[i].Value;
}
void AddCallSite(ServiceCallSite callSite, int index){
  slot++;
   //比如: 注册了ITest<>的两个实现类:Test<>,TestTest(),Test的生命周期是单例,TestTest的生命周期是瞬时,那么IEnumerable<ITest<xxx>>的生命周期就是瞬时
  cacheLocation = GetCommonCacheLocation(cacheLocation, callSite.Cache.Location);
  callSitesByIndex.Add(new(index, callSite));
}
}
ResultCache resultCache = 
(cacheLocation == CallSiteResultCacheLocation.Scope 
 || cacheLocation == CallSiteResultCacheLocation.Root)
? new ResultCache(cacheLocation, callSiteKey)
: new ResultCache(CallSiteResultCacheLocation.None, callSiteKey);
return _callSiteCache[callSiteKey] = new IEnumerableCallSite(resultCache, itemType, callSites);
}
finally{
callSiteChain.Remove(serviceIdentifier);
}
}

从上面可得,IEnumerable的生命周期的生命周期取决于,注册到serviceCollection中同一类型的ServiceKey的所有服务的生命周期范围的最小范围。

那GetService<IEnumerable>应该如何使用呢?

public static void Main(string[] args){
IServiceCollection services = new ServiceCollection();
services.Add(ServiceDescriptor.Singleton(typeof(DemoOne), typeof(DemoOne)));
services.Add(ServiceDescriptor.Singleton(typeof(DemoOne), typeof(DemoOne)));

//Test,TestTests实现了ITest接口
services.Add(ServiceDescriptor.Singleton(typeof(ITest<>), typeof(Test<>)));
services.Add(ServiceDescriptor.Singleton(typeof(ITest<>), typeof(TestTest<>)));

var serviceFactory = new DefaultServiceProviderFactory();
IServiceProvider serviceProvider = serviceFactory.CreateServiceProvider(services);

var demo1 = serviceProvider.GetService<IEnumerable<ITest<DemoOne>>>().ToList();
Console.WriteLine(demo1.Count); // 输出:2

var demo2 = serviceProvider.GetService<IEnumerable<DemoOne>>().ToList();
Console.WriteLine(demo2.Count); // 输出:2

}

(4)相同类型服务注册多个,会不会多个都生效呢?

已知,GetService方法拿三种类型的服务:

  • 准确型参数

  • 泛型参数

  • IEnumerable<>参数

  • IEnumerable<精确型参数>参数

  • IEnumerable<泛型参数>参数

问题三中已经说了使用GetService()获取IEnumerable<>参数。

准确型参数可看一下代码:

private ServiceCallSite? TryCreateExact(
ServiceIdentifier serviceIdentifier, 
CallSiteChain callSiteChain){
//看过我前面博客的就知道ServiceDescriptorCacheItem是什么
if (_descriptorLookup.TryGetValue(serviceIdentifier, out ServiceDescriptorCacheItem descriptor)){
  //这里descriptor.Last 相当于取了 ServiceDescriptorCacheItem 中的 _items.last,就是取了最后一个注册进来的服务
  return TryCreateExact(descriptor.Last, serviceIdentifier, callSiteChain, DefaultSlot);
}
if (serviceIdentifier.ServiceKey != null){
  var catchAllIdentifier = new ServiceIdentifier(KeyedService.AnyKey, serviceIdentifier.ServiceType);
  if (_descriptorLookup.TryGetValue(catchAllIdentifier, out descriptor)){
     //这里descriptor.Last 相当于取了 ServiceDescriptorCacheItem 中的 _items.last,就是取了最后一个注册进来的服务
    return TryCreateExact(descriptor.Last, serviceIdentifier, callSiteChain, DefaultSlot);
  }
}
return null;
}

泛型参数可看一下代码:

private ServiceCallSite? TryCreateOpenGeneric(
  ServiceIdentifier serviceIdentifier, 
  CallSiteChain callSiteChain){
  if (serviceIdentifier.IsConstructedGenericType){
    var genericIdentifier = serviceIdentifier.GetGenericTypeDefinition();
    if (_descriptorLookup.TryGetValue(genericIdentifier, out ServiceDescriptorCacheItem descriptor)){
      //这里descriptor.Last 相当于取了 ServiceDescriptorCacheItem 中的 _items.last,就是取了最后一个注册进来的服务
      return TryCreateOpenGeneric(descriptor.Last, serviceIdentifier, callSiteChain, DefaultSlot, true);
    }
    if (serviceIdentifier.ServiceKey != null){
      var catchAllIdentifier = new ServiceIdentifier(KeyedService.AnyKey, genericIdentifier.ServiceType);
      if (_descriptorLookup.TryGetValue(catchAllIdentifier, out descriptor)){
      //这里descriptor.Last 相当于取了 ServiceDescriptorCacheItem 中的 _items.last,就是取了最后一个注册进来的服务
        return TryCreateOpenGeneric(descriptor.Last, serviceIdentifier, callSiteChain, DefaultSlot, true);
      }
    }
  }
  return null;
}

由此可得:使用GetService方法拿 准确型参数以及泛型参数的服务是只会取最后一次注册的那个服务的。

  • 12
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值