回顧
通過前兩節的學習,我們知道 IServiceCollection 以元數據(ServiceDescriptor)的形式存放着用戶注冊的服務,它的 IServiceCollection 的拓展方法 BuildServiceProvider 為我們提供一個默認的容器 ServiceProvider,然而創建實例對象的任務並不是由他完成的,具體的是引擎 IServiceProviderEngine(更准確點是抽象類 ServiceProviderEngine) 類型來完成的,可以這么說,整個創建對象的核心功能,都由此抽象類控制完成。具體如下:‘
1、具備(根)節點(ServiceProviderEngineScope)控制對象生命周期
2、使用運行時動態創建對象(CallSiteRuntimeResolver),聽起來高級其實就是使用 Activator 這個類的封裝和重構創建實例的邏輯
3、存儲了創建服務實例的委托(RealizedServices)
4、使用 CallSiteFactory 遞歸地解析服務實例類型的創建方式(IServiceCallSite)
5、創建實例
IServiceProvider 是如何創建的?
在第一節最后我們當時猜測 IServiceProvider 的生命周期可能是Scoped ,接下來我們驗證下 IServiceProvider 的創建過程
IServiceCollection services = new ServiceCollection(); var root = services.BuildServiceProvider(); var service1 = root.GetService<IServiceProvider>(); var service2 = root.GetService<IServiceProvider>(); Console.WriteLine(ReferenceEquals(service1, service2)); Console.WriteLine(ReferenceEquals((root as ServiceProvider)._engine.RootScope, service1));
這里我創建一個默認容器但是沒有注冊任何服務,然后用容器創建了兩個 IServiceProvider,接着我們發現,兩個 service 是同一個引用,並且和引擎中的根相同,接下來我們開始 debug
internal abstract class ServiceProviderEngine : IServiceProviderEngine, IServiceScopeFactory { protected ServiceProviderEngine(IEnumerable<ServiceDescriptor> serviceDescriptors, IServiceProviderEngineCallback callback) { _createServiceAccessor = CreateServiceAccessor; CallSiteFactory = new CallSiteFactory(serviceDescriptors); CallSiteFactory.Add(typeof(IServiceProvider), new ServiceProviderCallSite()); CallSiteFactory.Add(typeof(IServiceScopeFactory), new ServiceScopeFactoryCallSite()); } private Func<ServiceProviderEngineScope, object> CreateServiceAccessor(Type serviceType) { var callSite = CallSiteFactory.CreateCallSite(serviceType, new CallSiteChain()); if (callSite != null) { _callback?.OnCreate(callSite); return RealizeService(callSite); } return _ => null; } internal object GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope) { var realizedService = RealizedServices.GetOrAdd(serviceType, _createServiceAccessor); _callback?.OnResolve(serviceType, serviceProviderEngineScope); return realizedService.Invoke(serviceProviderEngineScope); } }
由於第一次創建 IServiceProvider,所以 RealizedServices 中沒有該創建該服務的委托,接着調用 CreateServiceAccessor 獲取創建 IServiceProvider 的委托,我們發現最后的委托依然是抽象方法 RealizeService 返回的,但是抽象方法需要一個 IServiceCallSite 對象,才能返回創建該 IServiceCallSite(中的實例類型)的委托,有點繞,但是這里說明了創建實例不是一個簡單的 Type 就能提供的,因為實例可能存在有參構造函數,如何解析有參構造並且首先創建構造函數中的服務就成了 IServiceCallSite 的核心任務,所以我們可以把它稱為創建對象的依據。那我們來看 CallSiteFactory 是如何獲取服務的依據的
internal class CallSiteFactory { private readonly List<ServiceDescriptor> _descriptors; private readonly Dictionary<Type, IServiceCallSite> _callSiteCache = new Dictionary<Type, IServiceCallSite>(); private readonly Dictionary<Type, ServiceDescriptorCacheItem> _descriptorLookup = new Dictionary<Type, ServiceDescriptorCacheItem>(); internal IServiceCallSite CreateCallSite(Type serviceType, CallSiteChain callSiteChain) { lock (_callSiteCache) { if (_callSiteCache.TryGetValue(serviceType, out var cachedCallSite)) { return cachedCallSite; } } } }
首先從依據緩存(_callSiteCache)獲取,很幸運,在 ServiceProviderEngine 的初始化過程中,微軟為我們提供了 IServiceProvider 和 IServiceScopeFactory 的創建依據,分別是 ServiceProviderCallSite和 ServiceScopeFactoryCallSite,這里拿到依據接下來就交給 DynamicServiceProviderEngine 處理(RealizeService 是一個抽象方法,調用最遠實現)
public class DynamicServiceProviderEngine : CompiledServiceProviderEngine { protected override Func<ServiceProviderEngineScope, object> RealizeService(IServiceCallSite callSite) { var callCount = 0; return scope => { if (Interlocked.Increment(ref callCount) == 2) { Task.Run(() => base.RealizeService(callSite)); } return RuntimeResolver.Resolve(callSite, scope); }; } }
實際創建方法仍然是抽象類提供的,此外如果是第二次根據該依據創建實例,就會被父類 CompiledServiceProviderEngine 將創建創建實例的方法翻譯成表達式樹在轉換為委托存儲在 RealizedService 中,此時要注意的是一直是創建委托的過程,並沒有真正執行 DynamicServiceProviderEngine 提供的方法,這樣一來創建 IServiceProvider 的委托就已經有了,傳遞一個 ServiceProviderEngineScope 給委托就可以完成實例的創建,我們看具體的創建過程,這個時候又會調到 DynamicServiceProviderEngine 中提供的根據依據創建實例的方法,然后調用 CallSiteRuntimeResolver 的 Resolve 方法
public class CallSiteRuntimeResolver : CallSiteVisitor<ServiceProviderEngineScope, object> { public object Resolve(IServiceCallSite callSite, ServiceProviderEngineScope scope) { return VisitCallSite(callSite, scope); } protected override object VisitServiceProvider(ServiceProviderCallSite serviceProviderCallSite, ServiceProviderEngineScope scope) { return scope; } }
調用父類的實現,switch 判斷出是一個 ServiceProviderCallSite,接着調用抽象方法 VisitServiceProvider 又跳轉到子類中的實現,返回 scope
public abstract class CallSiteVisitor<TArgument, TResult> { protected virtual TResult VisitCallSite(IServiceCallSite callSite, TArgument argument) { switch (callSite) { case FactoryCallSite factoryCallSite: return VisitFactory(factoryCallSite, argument); case IEnumerableCallSite enumerableCallSite: return VisitIEnumerable(enumerableCallSite, argument); case ConstructorCallSite constructorCallSite: return VisitConstructor(constructorCallSite, argument); case TransientCallSite transientCallSite: return VisitTransient(transientCallSite, argument); case SingletonCallSite singletonCallSite: return VisitSingleton(singletonCallSite, argument); case ScopedCallSite scopedCallSite: return VisitScoped(scopedCallSite, argument); case ConstantCallSite constantCallSite: return VisitConstant(constantCallSite, argument); case CreateInstanceCallSite createInstanceCallSite: return VisitCreateInstance(createInstanceCallSite, argument); case ServiceProviderCallSite serviceProviderCallSite: return VisitServiceProvider(serviceProviderCallSite, argument); case ServiceScopeFactoryCallSite scopeFactoryCallSite: return VisitServiceScopeFactory(scopeFactoryCallSite, argument); default: throw new NotSupportedException($"Call site type {callSite.GetType()} is not supported"); } } protected abstract TResult VisitServiceProvider(ServiceProviderCallSite serviceProviderCallSite, TArgument argument); }
這里我們驗證了,通過容器獲取 IServiceProvider,得到的始終是該容器的根!類似的,我們還可以通過此方式 debug 一遍發現通過容器獲取服務 IServiceScopeFactory,返回的始終是該容器的引擎。
第一個 ITransient 實例是如何創建的?
通過對服務 IServiceProvider 創建過程的了解,我們想必也知道了,創建任何服務最終都會首先找到依據(IServiceCallSite),然后根據依據創建實例
private Func<ServiceProviderEngineScope, object> CreateServiceAccessor(Type serviceType) { var callSite = CallSiteFactory.CreateCallSite(serviceType, new CallSiteChain()); if (callSite != null) { _callback?.OnCreate(callSite); return RealizeService(callSite); } return _ => null; } internal object GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope) { var realizedService = RealizedServices.GetOrAdd(serviceType, _createServiceAccessor); _callback?.OnResolve(serviceType, serviceProviderEngineScope); return realizedService.Invoke(serviceProviderEngineScope); }
由於第一次創建 ITransient 服務,依據緩存中並沒有創建該服務的依據,我們看在 CreateCallSite 中是如何創建依據的
internal IServiceCallSite CreateCallSite(Type serviceType, CallSiteChain callSiteChain) { lock (_callSiteCache) { if (_callSiteCache.TryGetValue(serviceType, out var cachedCallSite)) { return cachedCallSite; } IServiceCallSite callSite; try { callSiteChain.CheckCircularDependency(serviceType); callSite = TryCreateExact(serviceType, callSiteChain) ?? TryCreateOpenGeneric(serviceType, callSiteChain) ?? TryCreateEnumerable(serviceType, callSiteChain); } finally { callSiteChain.Remove(serviceType); } _callSiteCache[serviceType] = callSite; return callSite; } }
創建依據(IServiceCallSite)時會依次嘗試用三種方式,他們分別是簡單實例、自定義泛型、IEnumerable泛型,其實,我們注冊的服務基本上都是通過第一種方式就可以找到依據
private IServiceCallSite TryCreateExact(ServiceDescriptor descriptor, Type serviceType, CallSiteChain callSiteChain) { if (serviceType == descriptor.ServiceType) { IServiceCallSite callSite; if (descriptor.ImplementationInstance != null) { callSite = new ConstantCallSite(descriptor.ServiceType, descriptor.ImplementationInstance); } else if (descriptor.ImplementationFactory != null) { callSite = new FactoryCallSite(descriptor.ServiceType, descriptor.ImplementationFactory); } else if (descriptor.ImplementationType != null) { callSite = CreateConstructorCallSite(descriptor.ServiceType, descriptor.ImplementationType, callSiteChain); } else { throw new InvalidOperationException("Invalid service descriptor"); } return ApplyLifetime(callSite, descriptor, descriptor.Lifetime); } return null; }
在多個元數據(ServiceDescriptor)中,通過最后一個注冊的元數據來創建依據,因為我們注冊的實例方式必然是實例類型、實例對象、實例工廠中的一個,這點從元數據的構造器也可以看出來
public class ServiceDescriptor { public ServiceDescriptor( Type serviceType, Type implementationType, ServiceLifetime lifetime) : this(serviceType, lifetime) { ImplementationType = implementationType; } public ServiceDescriptor( Type serviceType, object instance) : this(serviceType, ServiceLifetime.Singleton) { ImplementationInstance = instance; } public ServiceDescriptor( Type serviceType, Func<IServiceProvider, object> factory, ServiceLifetime lifetime) : this(serviceType, lifetime) { ImplementationFactory = factory; } }
現在我們已知注冊了服務 ITransient,實例類型為 Transient,卻可以這樣獲取實例
IServiceCollection services = new ServiceCollection(); services.AddTransient<ITransient, Transient>(); var serviceProvider = services.BuildServiceProvider(); var transientArray = serviceProvider.GetService<IEnumerable<ITransient>>(); Console.WriteLine(transientArray.GetType().FullName);
輸出結果為 Microsoft.Extensions.DependencyInjection.ITransient[],這是根據元數據創建依據三種方式(簡單實例、自定義泛型、IEnumerable泛型)的第三種,因為在元數據中找不到一個服務類型 IEnumerable<ITransient>,但是如果是泛型 IEnumerable<>,仍然也會創建對象,在 CallSiteFactory 的 TryCreateEnumerable 方法中可以看到,最后返回的依據是一個 IEnumerableCallSite 類型,從輸出結果我們可以看到,它的最終實例是一個數組
private IServiceCallSite TryCreateEnumerable(Type serviceType, CallSiteChain callSiteChain) { if (serviceType.IsConstructedGenericType && serviceType.GetGenericTypeDefinition() == typeof(IEnumerable<>)) { //省略了很多代碼 return new IEnumerableCallSite(itemType, callSites.ToArray()); } return null; }
那自定義泛型是什么意思呢?其實和 IEnumerableCallSite 類似,只不過在試着使用 IEnumerable 泛型創建依據之前,會使用自定義的泛型
internal IServiceCallSite CreateCallSite(Type serviceType, CallSiteChain callSiteChain) { callSite = TryCreateExact(serviceType, callSiteChain) ?? TryCreateOpenGeneric(serviceType, callSiteChain) ?? TryCreateEnumerable(serviceType, callSiteChain); }
由於在框架內部,微軟可以識別 IEnumerable 從而創建一個數組,但是如果是一個為之的泛型呢?比如以下
var instance = serviceProvider.GetService<IModelService<ITransient>>();
在用此方式創建依據時,微軟會檢測我們是否注入了 IModelService<> 服務(檢測元數據中有沒有它),最終的依據是 CreateConstructorCallSite
private IServiceCallSite TryCreateOpenGeneric(Type serviceType, CallSiteChain callSiteChain) { if (serviceType.IsConstructedGenericType && _descriptorLookup.TryGetValue(serviceType.GetGenericTypeDefinition(), out var descriptor)) { return TryCreateOpenGeneric(descriptor.Last, serviceType, callSiteChain); } return null; } private IServiceCallSite TryCreateOpenGeneric(ServiceDescriptor descriptor, Type serviceType, CallSiteChain callSiteChain) { if (serviceType.IsConstructedGenericType && serviceType.GetGenericTypeDefinition() == descriptor.ServiceType) { Debug.Assert(descriptor.ImplementationType != null, "descriptor.ImplementationType != null"); var closedType = descriptor.ImplementationType.MakeGenericType(serviceType.GenericTypeArguments); var constructorCallSite = CreateConstructorCallSite(serviceType, closedType, callSiteChain); return ApplyLifetime(constructorCallSite, Tuple.Create(descriptor, serviceType), descriptor.Lifetime); } return null; }
從而以下代碼得以正常執行
interface ITransient { } class Transient : ITransient { } interface IModelService<T> { } class ModelService<T> : IModelService<T> { } class Program { static void Main(string[] args) { IServiceCollection services = new ServiceCollection(); services.AddTransient<ITransient, Transient>(); services.AddTransient(typeof(IModelService<>), typeof(ModelService<>)); var serviceProvider = services.BuildServiceProvider(); var instance = serviceProvider.GetService<IModelService<ITransient>>(); } }
instance 的實際類型為 Microsoft.Extensions.DependencyInjection.ModelService`1[[Microsoft.Extensions.DependencyInjection.ITransient, DependencyCore, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]
到這里我們回到最初,看最簡單的,創建一個基本的 ITransient 服務依據時如何進行的!
private IServiceCallSite TryCreateExact(ServiceDescriptor descriptor, Type serviceType, CallSiteChain callSiteChain) { if (serviceType == descriptor.ServiceType) { IServiceCallSite callSite; if (descriptor.ImplementationInstance != null) { callSite = new ConstantCallSite(descriptor.ServiceType, descriptor.ImplementationInstance); } else if (descriptor.ImplementationFactory != null) { callSite = new FactoryCallSite(descriptor.ServiceType, descriptor.ImplementationFactory); } else if (descriptor.ImplementationType != null) { callSite = CreateConstructorCallSite(descriptor.ServiceType, descriptor.ImplementationType, callSiteChain); } else { throw new InvalidOperationException("Invalid service descriptor"); } return ApplyLifetime(callSite, descriptor, descriptor.Lifetime); } return null; }
由於注冊方式的差異,所以會有三種情況,這里我們只看以 services.AddTransient<ITransient, Transient>() 注冊的情形,它對應着 if 語句的第三個分支,來到 CreateConstructorCallSite 方法,其實我們早在之前就知道創建對象實際上是一個遞歸(構造器也可能存在服務)的過程,這個不完全正確,遞歸的過程在創建依據,因為依據一旦有了,微軟就會有序的根據依據創建實例!遞歸獲取參數的依據和最初獲取 ITransient 依據時一樣的只不過這里提供了一個 CallSiteChain 來處理循環創建的情形(循環創建同一個服務就會拋出異常)
private IServiceCallSite CreateConstructorCallSite(Type serviceType, Type implementationType, CallSiteChain callSiteChain) { callSiteChain.Add(serviceType, implementationType); var constructors = implementationType.GetTypeInfo().DeclaredConstructors.Where(constructor => constructor.IsPublic).ToArray(); IServiceCallSite[] parameterCallSites = null; if (constructors.Length == 0) {//沒有公有構造器 throw new InvalidOperationException(Resources.FormatNoConstructorMatch(implementationType)); } else if (constructors.Length == 1) { var constructor = constructors[0]; var parameters = constructor.GetParameters(); //沒有參數 if (parameters.Length == 0) { return new CreateInstanceCallSite(serviceType, implementationType); } //獲取每個參數的依據 parameterCallSites = CreateArgumentCallSites( serviceType, implementationType, callSiteChain, parameters, throwIfCallSiteNotFound: true); return new ConstructorCallSite(serviceType, constructor, parameterCallSites); } //處理有多個構造器的情形 //代碼省略 }
出現多個構造器的情形是,會遍歷每一個構造器,找到的第一個不為 null 的參數依據列表,那么這個構造器就是最終創建該實例的構造器,此外遍歷並沒有結束,如果該構造器中的參數類型集合不是剩余構造器的參數集合的超集,則會拋出異常,舉個例子就能明白,一下情形是不能正常實例化的,拋出異常的時候並沒有試圖創建 IScoped 和 ISingleton 中的任何一個實例,這點很重要!
interface ITransient { } class Transient : ITransient { public Transient(IFoo foo) { } public Transient(IScoped scoped,ISingleton singleton) { } }
由於我們注冊的 Transient 是沒有有參構造器的,所以我們拿到的依據時一個 CreateInstanceCallSite 類型,但是在 TryCreateExact 方法的最后並沒有直接返回它,而是通過 ApplyLifetime(callSite, descriptor, descriptor.Lifetime) 為其申請了一個生命周期,再做返回。
因為 IServiceCallSite 是創建實例的依據,但是我們發現 CreateInstanceCallSite 並沒有和生命周期相關的字段,所以最后返回的常常是一個具有生命周期的依據包裹一個具有創建邏輯(構造器中的服務也)的依據!最后返回的是一個依據是 TransientCallSite
public IServiceCallSite ApplyLifetime(IServiceCallSite serviceCallSite, object cacheKey, ServiceLifetime descriptorLifetime) { if (serviceCallSite is ConstantCallSite) { return serviceCallSite; } switch (descriptorLifetime) { case ServiceLifetime.Transient: return new TransientCallSite(serviceCallSite); case ServiceLifetime.Scoped: return new ScopedCallSite(serviceCallSite, cacheKey); case ServiceLifetime.Singleton: return new SingletonCallSite(serviceCallSite, cacheKey); default: throw new ArgumentOutOfRangeException(nameof(descriptorLifetime)); } }
由於第一次創建(實際運行時不管是第一次還是是第二次)將調用 DynamicServiceProviderEngine 中重寫的方法提供根據依據創建實例的委托,拿到這個委托后,首先緩存在 RealizedService 中,然后傳遞根,執行該委托!隨后我們又來到了 CallSiteRuntimeResolver 這個類中,在子類中判斷依據類型是 TransientCallSite,然后調用下面的方法,到這里我們發現還沒有創建實例,僅僅知道了它的生命周期是 Transient,然后通過 TransientCallSite 內部包裹的具有創建邏輯的 IServiceCallSite,去創建實例,拿到實例后,執行 scope 的的 CaptureDisposable 方法將實例存儲到根的釋放隊列中(隨着根的釋放被釋放)
protected override object VisitTransient(TransientCallSite transientCallSite, ServiceProviderEngineScope scope) { return scope.CaptureDisposable( VisitCallSite(transientCallSite.ServiceCallSite, scope)); }
那實例是如何創建的呢?這里再次調用基類的方法 VisitCallSite 方法判斷出依據是一個 CreateInstanceCallSite 類型,然后執行 VisitCreateInstance 方法創建實例
protected override object VisitCreateInstance(CreateInstanceCallSite createInstanceCallSite, ServiceProviderEngineScope scope) { try { return Activator.CreateInstance(createInstanceCallSite.ImplementationType); } catch (Exception ex) when (ex.InnerException != null) { ExceptionDispatchInfo.Capture(ex.InnerException).Throw(); // The above line will always throw, but the compiler requires we throw explicitly. throw; } }
IServiceCallSite 依據一覽
public interface IServiceCallSite { Type ServiceType { get; } Type ImplementationType { get; } }
依據的原型很簡單,包含了服務類型和實現類型,我們看實現 Ctrl + 12
具有生命周期的 IServiceCallSite 有:
1、TransientCallSite
2、ScopedCallSite
3、SingletonCallSite
提供創建方式的 IServiceCallSite 有:
1、IEnumerableCallSite
2、CreateInstanceCallSite
3、ServiceScopeFactoryCallSite
4、ServiceProviderCallSite
5、ConstructorCallSite
6、ConstantCallSite
7、FactoryCallSite
當然並非所有的服務都具有某種意義上的生命周期,從提供創建方式的依據的3、4條也可以看出來,CallSiteVisitor 是如何利用這些依據創建對象的呢?
抽象工廠+多態創建實例
public abstract class CallSiteVisitor<TArgument, TResult> { protected virtual TResult VisitCallSite(IServiceCallSite callSite, TArgument argument) { switch (callSite) { case FactoryCallSite factoryCallSite: return VisitFactory(factoryCallSite, argument); case IEnumerableCallSite enumerableCallSite: return VisitIEnumerable(enumerableCallSite, argument); case ConstructorCallSite constructorCallSite: return VisitConstructor(constructorCallSite, argument); case TransientCallSite transientCallSite: return VisitTransient(transientCallSite, argument); case SingletonCallSite singletonCallSite: return VisitSingleton(singletonCallSite, argument); case ScopedCallSite scopedCallSite: return VisitScoped(scopedCallSite, argument); case ConstantCallSite constantCallSite: return VisitConstant(constantCallSite, argument); case CreateInstanceCallSite createInstanceCallSite: return VisitCreateInstance(createInstanceCallSite, argument); case ServiceProviderCallSite serviceProviderCallSite: return VisitServiceProvider(serviceProviderCallSite, argument); case ServiceScopeFactoryCallSite scopeFactoryCallSite: return VisitServiceScopeFactory(scopeFactoryCallSite, argument); default: throw new NotSupportedException($"Call site type {callSite.GetType()} is not supported"); } } protected abstract TResult VisitTransient(TransientCallSite transientCallSite, TArgument argument); protected abstract TResult VisitConstructor(ConstructorCallSite constructorCallSite, TArgument argument); protected abstract TResult VisitSingleton(SingletonCallSite singletonCallSite, TArgument argument); protected abstract TResult VisitScoped(ScopedCallSite scopedCallSite, TArgument argument); protected abstract TResult VisitConstant(ConstantCallSite constantCallSite, TArgument argument); protected abstract TResult VisitCreateInstance(CreateInstanceCallSite createInstanceCallSite, TArgument argument); protected abstract TResult VisitServiceProvider(ServiceProviderCallSite serviceProviderCallSite, TArgument argument); protected abstract TResult VisitServiceScopeFactory(ServiceScopeFactoryCallSite serviceScopeFactoryCallSite, TArgument argument); protected abstract TResult VisitIEnumerable(IEnumerableCallSite enumerableCallSite, TArgument argument); protected abstract TResult VisitFactory(FactoryCallSite factoryCallSite, TArgument argument); }
CallSiteVisitor 這個抽象類是非常有趣的,它像是一個生產器,接受一個有多態特性的依據(IServiceCallSite)和一個參數 TArgument,創建一個 TResult。在 VisisCallSite 方法中,它更像是一個抽象工廠,但是本身又沒有提供真正邏輯,所有獲取 TResult 的邏輯都將在子類中得到重寫。他有三個子類
1、CallSiteRuntimeResolver,運行時解析器,它根據 IServiceCallSite 以及 ServiceProviderEngineScope,獲取實例
2、CallSiteExpressionBuilder,將創建實例的方法轉換成表達式樹
3、CallSiteValidator,和作用域相關
ServiceProviderEngineScope 是如何結合 ServiceProviderEngine 完成 Scoped 和 Singleton 這兩種是生命周期的管理的?
我們看運行時解析器中的兩個方法,通過 Scoped、Singleton 注冊的服務獲得的依據分別是 ScopedCallSite、SingletonCallSite,在抽象類 CallSiteVisitor 的 VisisCallSite 方法中我們可以知道最終會從以 CallSiteRuntimeResolver 中的以下兩個方法來創建實例
protected override object VisitSingleton(SingletonCallSite singletonCallSite, ServiceProviderEngineScope scope) { return VisitScoped(singletonCallSite, scope.Engine.Root); } protected override object VisitScoped(ScopedCallSite scopedCallSite, ServiceProviderEngineScope scope) { lock (scope.ResolvedServices) { if (!scope.ResolvedServices.TryGetValue(scopedCallSite.CacheKey, out var resolved)) { resolved = VisitCallSite(scopedCallSite.ServiceCallSite, scope); scope.CaptureDisposable(resolved); scope.ResolvedServices.Add(scopedCallSite.CacheKey, resolved); } return resolved; } }
這里我們發現這兩種方式獲取的實例都是在 ServiceProviderEngineScope 中取得的,只不過一個 Singleton 是在引擎的根 ServiceProviderEngineScope 獲取緩存的實例對象,另一個是在當前根中獲取緩存的實例對象!