這個系列已經寫了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)
[Asp.net 5] DependencyInjection項目代碼分析4-微軟的實現(3)
如果想對本篇有個更好的了解,建議需要先看
“[Asp.net 5] DependencyInjection項目代碼分析”
“[Asp.net 5] DependencyInjection項目代碼分析4-微軟的實現(1)”
“[Asp.net 5] DependencyInjection項目代碼分析4-微軟的實現(2)”。
"[Asp.net 5] DependencyInjection項目代碼分析4-微軟的實現(3)"
繼續ServicePRovider類
在之前的講解中我們提到過Service類調用CreateCallSite方法時會遞歸調用,但是我們沒具體說明如何遞歸調的。實際上Service類,通過反射創建實例的時候,會實例化的參數對象,而實例話參數對象通過ServiceProvider類創建,而ServiceProvider類創建參數的實例,又需要通過Service類(如果是通過Type注冊的)創建。下面我們把Service的CreateInstanceCallSite方法以及ServiceProvider相關的方法列出來。
public IServiceCallSite CreateCallSite(ServiceProvider provider, ISet<Type> callSiteChain) { ConstructorInfo[] constructors = _descriptor.ImplementationType.GetTypeInfo() .DeclaredConstructors .Where(IsInjectable) .ToArray(); // TODO: actual service-fulfillment constructor selection if (constructors.Length == 1) { ParameterInfo[] parameters = constructors[0].GetParameters(); IServiceCallSite[] parameterCallSites = new IServiceCallSite[parameters.Length]; for (var index = 0; index != parameters.Length; ++index) { parameterCallSites[index] = provider.GetServiceCallSite(parameters[index].ParameterType, callSiteChain); if (parameterCallSites[index] == null && parameters[index].HasDefaultValue) { parameterCallSites[index] = new ConstantCallSite(parameters[index].DefaultValue); } if (parameterCallSites[index] == null) { throw new InvalidOperationException(Resources.FormatCannotResolveService( parameters[index].ParameterType, _descriptor.ImplementationType)); } } return new ConstructorCallSite(constructors[0], parameterCallSites); } return new CreateInstanceCallSite(_descriptor); }Service的CreateCallSite
internal IServiceCallSite GetServiceCallSite(Type serviceType, ISet<Type> callSiteChain) { try { if (callSiteChain.Contains(serviceType)) { throw new InvalidOperationException(Resources.FormatCircularDependencyException(serviceType)); } callSiteChain.Add(serviceType); ServiceEntry entry; if (_table.TryGetEntry(serviceType, out entry)) { return GetResolveCallSite(entry.Last, callSiteChain); } object emptyIEnumerableOrNull = GetEmptyIEnumerableOrNull(serviceType); if (emptyIEnumerableOrNull != null) { return new EmptyIEnumerableCallSite(serviceType, emptyIEnumerableOrNull); } return null; } finally { callSiteChain.Remove(serviceType); } } internal IServiceCallSite GetResolveCallSite(IService service, ISet<Type> callSiteChain) { IServiceCallSite serviceCallSite = service.CreateCallSite(this, callSiteChain); if (service.Lifetime == ServiceLifetime.Transient) { return new TransientCallSite(serviceCallSite); } else if (service.Lifetime == ServiceLifetime.Scoped) { return new ScopedCallSite(service, serviceCallSite); } else { return new SingletonCallSite(service, serviceCallSite); } }ServiceProvider
對于Service的CreateCallSite方法,之前我們已經介紹過,現在我們重點講下ServiceProvider的GetServiceCallSite方法。從上面代碼中我們發現參數中含有“ISet<Type> callSiteChain”,這個參數是防止發生A的構造函數有B類型參數,B的構織函數中有A類型參數,當A,B都是通過類型注入的,那么系統會陷入死循環。而callSiteChain得作用就是防止這樣的死循環發生,當創建A時,會在callSiteChain中查詢歷史中是否有A的創建過程,如果有則說明發生死循環了,直接拋出異常,結束;如果沒有將A加入到callSiteChain中,繼續創建其參數。GetResolveCallSite方法比較簡單,對于ServiceProvider已經能夠獲取的IServiceCallSite實例,進行包裝,已保證生成的實例能夠適應不同的Scoped(該處應該使用設計模式中的代理模式,不過我設計模式不過關,請幫忙確認)。
對于TransientCallSite、ScopedCallSite、SingletonCallSite以及EmptyIEnumerableCallSite代碼,如下所示:
private class EmptyIEnumerableCallSite : IServiceCallSite { private readonly object _serviceInstance; private readonly Type _serviceType; public EmptyIEnumerableCallSite(Type serviceType, object serviceInstance) { _serviceType = serviceType; _serviceInstance = serviceInstance; } public object Invoke(ServiceProvider provider) { return _serviceInstance; } public Expression Build(Expression provider) { return Expression.Constant(_serviceInstance, _serviceType); } } private class TransientCallSite : IServiceCallSite { private readonly IServiceCallSite _service; public TransientCallSite(IServiceCallSite service) { _service = service; } public object Invoke(ServiceProvider provider) { return provider.CaptureDisposable(_service.Invoke(provider)); } public Expression Build(Expression provider) { return Expression.Call( provider, CaptureDisposableMethodInfo, _service.Build(provider)); } } private class ScopedCallSite : IServiceCallSite { private readonly IService _key; private readonly IServiceCallSite _serviceCallSite; public ScopedCallSite(IService key, IServiceCallSite serviceCallSite) { _key = key; _serviceCallSite = serviceCallSite; } public virtual object Invoke(ServiceProvider provider) { object resolved; lock (provider._sync) { if (!provider._resolvedServices.TryGetValue(_key, out resolved)) { resolved = provider.CaptureDisposable(_serviceCallSite.Invoke(provider));
新聞熱點
疑難解答