zoukankan      html  css  js  c++  java
  • [Asp.net 5] DependencyInjection项目代码分析4-微软的实现(5)(IEnumerable<>补充)

    Asp.net 5的依赖注入注入系列可以参考链接: [Asp.net 5] DependencyInjection项目代码分析-目录

    我们在之前讲微软的实现时,对于OpenIEnumerableService与ClosedIEnumerableService抛下没讲,现在我们就将该部分补充完整。

    我们回忆ServiceProvider类的构造函数(对外部使用的)中,注册了IEnumerable<>、new OpenIEnumerableService(_table)的关系。

            public ServiceProvider(IEnumerable<ServiceDescriptor> serviceDescriptors)
            {
                _root = this;
                _table = new ServiceTable(serviceDescriptors);
    
                _table.Add(typeof(IServiceProvider), new ServiceProviderService());
                _table.Add(typeof(IServiceScopeFactory), new ServiceScopeService());
                _table.Add(typeof(IEnumerable<>), new OpenIEnumerableService(_table));
            }
    ServiceProvider构造函数

    因为IEnumerable是泛型,所以我们可以推断OpenIEnumerableService类应该实现IGenericService接口。那么如果我们想查找IEnumerable<T>的实现类中间会有怎样的过程呢?

    • [步骤1]首先系统会查找在ServiceTable内部_services(Dictionary<Type, ServiceEntry>类型)是否有注册过IEnumerable<T>类型,如果有注册直接返回实现类中最后一个。下面是直接包含IEnumerable<T>的原因
      • 系统可以显示的注册IEnumerable<T>,比如services.AddTransient<IEnumerable<T>, List<T>>();
      • 系统也可能之前获取过IEnumerable<T>,所以_services中有上次结果的缓存。
    • [步骤2]如果没有找到相应的IEnumerable<T>,系统会继续通过_genericServices(Dictionary<Type, List<IGenericService>>类型)查找IEnumerable<>,与通过_services方式获取不同,通过_genericServices会获取到的是所有注册过IEnumerable<>类型对应的IGenericService列表(List类型,包含顺序)并不是单一一个IGenericService;之后顺序遍历IGenericService列表,将IEnumerable<T>/IGenericService.GetService()的对应关系添加到services中,重复[步骤1]的操作获取。
      • 如果系统没额外注册IEnumerable<>类型,那么_genericServices的列表中只能获取唯一的注册项OpenIEnumerableService,那么相应的操作则在OpenIEnumerableService中进行。
      • 如果系统额外注册IEnumerable<>类型(假设为GenericService1),那么在注册列表中GenericService1一定排在OpenIEnumerableService之后。所以当获取IEnumerable<T>时,OpenIEnumerableService.GetService()与GenericService1.GetService()返回值一定都会添加到_services中,但是GenericService1.GetService()一定在后面,所以IEnumerable<T>的实现类一定是GenericService1.GetService().CreateCallSite().Invoke()的值;换句话说GenericService1会将OpenIEnumerableService覆盖掉。
      • 由于注册IEnumerable<>会覆盖掉OpenIEnumerableService,所以原则上不允许注册IEnumerable<>类型

    OpenIEnumerableService与ClosedIEnumerableService

    由于OpenIEnumerableService实现IGenericService接口,所以会返回IService类型的对象,该对象是ClosedIEnumerableService类型。ClosedIEnumerableService类型内部实际上返回的是ServiceTable中_services所有T的注册项,之后以IEnumerable<T>类型返回。

        internal class OpenIEnumerableService : IGenericService
        {
            private readonly ServiceTable _table;
    
            public OpenIEnumerableService(ServiceTable table)
            {
                _table = table;
            }
    
            public ServiceLifetime Lifetime
            {
                get { return ServiceLifetime.Transient; }
            }
    
            public IService GetService(Type closedServiceType)
            {
                var itemType = closedServiceType.GetTypeInfo().GenericTypeArguments[0];
    
                ServiceEntry entry;
                return _table.TryGetEntry(itemType, out entry) ?
                    new ClosedIEnumerableService(itemType, entry) :
                    null;
            }
        }
    OpenIEnumerableService
        internal class ClosedIEnumerableService : IService
        {
            private readonly Type _itemType;
            private readonly ServiceEntry _serviceEntry;
    
            public ClosedIEnumerableService(Type itemType, ServiceEntry entry)
            {
                _itemType = itemType;
                _serviceEntry = entry;
            }
    
            public IService Next { get; set; }
    
            public ServiceLifetime Lifetime
            {
                get { return ServiceLifetime.Transient; }
            }
    
            public IServiceCallSite CreateCallSite(ServiceProvider provider, ISet<Type> callSiteChain)
            {
                var list = new List<IServiceCallSite>();
                for (var service = _serviceEntry.First; service != null; service = service.Next)
                {
                    list.Add(provider.GetResolveCallSite(service, callSiteChain));
                }
                return new CallSite(_itemType, list.ToArray());
            }
    
            private class CallSite : IServiceCallSite
            {
                private readonly Type _itemType;
                private readonly IServiceCallSite[] _serviceCallSites;
    
                public CallSite(Type itemType, IServiceCallSite[] serviceCallSites)
                {
                    _itemType = itemType;
                    _serviceCallSites = serviceCallSites;
                }
    
                public object Invoke(ServiceProvider provider)
                {
                    var array = Array.CreateInstance(_itemType, _serviceCallSites.Length);
                    for (var index = 0; index != _serviceCallSites.Length; ++index)
                    {
                        array.SetValue(_serviceCallSites[index].Invoke(provider), index);
                    }
                    return array;
                }
    
                public Expression Build(Expression provider)
                {
                    return Expression.NewArrayInit(
                        _itemType,
                        _serviceCallSites.Select(callSite =>
                            Expression.Convert(
                                callSite.Build(provider),
                                _itemType)));
                }
            }
        }
    ClosedIEnumerableService

    [之前我们介绍ServiceEntry时,明确指出是链表结构,而不是单独存放一个值;其应用在这进行了淋漓尽致的表现]

  • 相关阅读:
    并发编程三要素:原子性,有序性,可见性
    【华为云技术分享】【Python成长之路】来聊聊多线程的几位“辅助”
    【华为云技术分享】根因分析
    【华为云技术分享】浅谈服务化和微服务化(下)
    【华为云技术分享】浅谈服务化和微服务化(上)
    【华为云技术分享】STM32 GPIO的原理、特性、选型和配置
    【华为云技术分享】快速理解spark-on-k8s中的external-shuffle-service
    【华为云技术分享】如何设计高质量软件-领域驱动设计DDD(Domain-Driven Design)学习心得
    【华为云技术分享】唐老师带你秒懂大数据,以及Spark和Flink在干啥咧
    【华为云技术分享】昇腾AI处理器软件栈--总览
  • 原文地址:https://www.cnblogs.com/watermoon2/p/4558837.html
Copyright © 2011-2022 走看看