[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时,明确指出是链表结构,而不是单独存放一个值;其应用在这进行了淋漓尽致的表现]

时间: 2024-10-19 03:45:16

[Asp.net 5] DependencyInjection项目代码分析4-微软的实现(5)(IEnumerable<>补充)的相关文章

[Asp.net 5] DependencyInjection项目代码分析4-微软的实现(3)

这个系列已经写了5篇,链接地址如下: [Asp.net 5] DependencyInjection项目代码分析 [Asp.net 5] DependencyInjection项目代码分析2-Autofac [Asp.net 5] DependencyInjection项目代码分析3-Ninject [Asp.net 5] DependencyInjection项目代码分析4-微软的实现(1) [Asp.net 5] DependencyInjection项目代码分析4-微软的实现(2) 如果想

[Asp.net 5] DependencyInjection项目代码分析-目录

微软DI文章系列如下所示: [Asp.net 5] DependencyInjection项目代码分析 [Asp.net 5] DependencyInjection项目代码分析2-Autofac [Asp.net 5] DependencyInjection项目代码分析3-Ninject [Asp.net 5] DependencyInjection项目代码分析4-微软的实现(1) [Asp.net 5] DependencyInjection项目代码分析4-微软的实现(2) [Asp.net

[Asp.net 5] DependencyInjection项目代码分析4-微软的实现(4)

这个系列已经写了6篇,链接地址如下: [Asp.net 5] DependencyInjection项目代码分析 [Asp.net 5] DependencyInjection项目代码分析2-Autofac [Asp.net 5] DependencyInjection项目代码分析3-Ninject [Asp.net 5] DependencyInjection项目代码分析4-微软的实现(1) [Asp.net 5] DependencyInjection项目代码分析4-微软的实现(2) [As

[Asp.net 5] DependencyInjection项目代码分析4-微软的实现(中)

在 DependencyInjection项目代码分析4-微软的实现(上)中介绍了“ServiceTable”.“ServiceEntry”.“IGenericService”.“IService”.“IServiceCallSite”,这篇介绍下“IGenericService."IService"."IServiceCallSite"实现类 GenericService类 做为IGenericService的唯一实现类,该类言简意赅,请看代码: internal

[Asp.net 5] DependencyInjection项目代码分析3-Ninject

Microsoft.Framework.DependencyInjection.Ninject 该工程内部共包含5个类文件,底层使用Ninject实现依赖注入,工程截图如下: 从文件命名可以看出,NinjectServiceProvider和NinjectServiceScopeFactory分别是接口IServiceProvider和IServiceScopeFactory的实现类. (IServiceScope接口的实现类作为NinjectServiceScopeFactory内部类而存在,

[Asp.net 5] DependencyInjection项目代码分析

最近在研究开源代码,正好发现Asp.net5的源码,下载地址:https://github.com/aspnet. 今天主要讲的是DependencyInjection这部分,抛砖引玉,供大家参考,也欢迎莅临斧正.闲话不多说,下面就代码进行简单分析 项目架构如下: 一共包含DependencyInjection.DependencyInjection.Abstractions.DependencyInjection.Autofac.DependencyInjection.Ninject以及Dep

[Asp.net 5] DependencyInjection项目代码分析2

Microsoft.Framework.DependencyInjection.Autofac源码分析 该工程只有一个代码静态类AutofacRegistration,但是该类有3个扩展方法,以及3个内部类.扩展方法如下: public static class AutofacRegistration { public static void Populate(this ContainerBuilder builder,IEnumerable<ServiceDescriptor> descri

[Asp.net 5] DependencyInjection项目代码分析4-微软的实现(上)

前面俩种实现中,很多内部细节都无法知道,微软的框架也是为了屏蔽具体实现,只让我们关注接口.但是人都是充满好奇的,依赖注入到底是怎么实现的呢? 微软又有怎样的实现呢?下面就为大家一一呈现(说实话,代码真不好读) 先看下核心类:ServiceTable internal class ServiceTable { private readonly object _sync = new object(); private readonly Dictionary<Type, ServiceEntry>

结对队友个人项目代码分析

项目要求 项目名称:中小学数学卷子自动生成程序 用户: 小学.初中和高中数学老师. 功能: 1.命令行输入用户名和密码,两者之间用空格隔开(程序预设小学.初中和高中各三个账号,具体见附表),如果用户名和密码都正确,将根据账户类型显示"当前选择为XX出题",XX为小学.初中和高中三个选项中的一个.否则提示"请输入正确的用户名.密码",重新输入用户名.密码: 2.登录后,系统提示"准备生成XX数学题目,请输入生成题目数量:",XX为小学.初中和高中三