[Asp.net 5] DependencyInjection項目程式碼分析4-微軟的實現(5)(IEnumerable<>補充)

來源:互聯網
上載者:User

標籤:

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時,明確指出是鏈表結構,而不是單獨存放一個值;其應用在這進行了淋漓盡致的表現]

[Asp.net 5] DependencyInjection項目程式碼分析4-微軟的實現(5)(IEnumerable<>補充)

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.