到目前为止,我们定义的ServiceProvider已经实现了基本的服务提供和回收功能,但是依然漏掉了一些必需的细节特性。这些特性包括如何针对IServiceProvider接口提供一个ServiceProvider对象,何创建ServiceScope,以及如何提供一个服务实例的集合。
一、提供一个ServiceProvider对象
我们知道当将服务类型指定为IServiceProvider接口并调用ServiceProvider的GetService方法是,ServiceProvider对象本身将会作为服务实例返回,这个特性可以利用一个自定义的Service来实现。如下面的代码片段所示,我们定义的这个ServiceProviderService既是一个Service,又是一个ServiceCallSite。它默认采用生命周期管理模式为Scoped,在Invoke和Build方法中,它直接将当前ServiceProvider作为提供的服务实例。在初始化ServiceTable的时候,我们额外添加一个针对ServiceProviderService的ServideEntry。
internal class ServiceProviderService : IService, IServiceCallSite { public ServiceLifetime Lifetime => ServiceLifetime.Scoped; public IService Next { get; set; } public Expression Build (Expression provider) { return provider; } public IServiceCallSite CreateCallSite (ServiceProvider provider, ISet<Type> callSiteChain) { return this; } public object Invoke (ServiceProvider provider) { return provider; } } internal class ServiceTable { public ServiceTable (IServiceCollection services) { //解析ServiceCollection并添加相应ServiceEntry this.ServieEntries[typeof (IServiceProvider)] = new ServiceEntry (new ServiceProviderService ()); } }
二、创建ServiceScope
创建ServiceScope的目的在于创建作为当前ServiceProvider儿子的另一个ServiceProvider,新创建的ServiceProvider不仅与原来的ServiceProvider具有相同的根,同时共享所有的服务注册信息。利用这个新的ServiceProvider来代替现有的ServiceProvider,其主要的目的还是使我们能够及时地回收提供的服务实例。ServiceScope是通过它的工厂ServiceScopeFactory来创建的,所以先创建了如下一个ServiceScopeFactory类和对应的ServiceScope,它们的定义与我们在前面一节介绍的完全一致。
internal class ServiceScope : IServiceScope { public IServiceProvider ServiceProvider { get; private set; } public ServiceScope (ServiceProvider serviceProvider) { this.ServiceProvider = serviceProvider; } public void Dispose () { (this.ServiceProvider as IDisposable)?.Dispose (); } } internal class ServiceScopeFactory : IServiceScopeFactory { public ServiceProvider ServiceProvider { get; private set; } public ServiceScopeFactory (ServiceProvider serviceProvider) { this.ServiceProvider = serviceProvider; } public IServiceScope CreateScope () { return new ServiceScope (this.ServiceProvider); } } internal class ServiceProvider : IServiceProvider, IDisposable { public ServiceProvider (ServiceProvider parent) { this.Root = parent.Root; this.ServiceTable = parent.ServiceTable; } }
为了让ServiceProvider的GetService方法在服务类型指定为IServiceScopeFactory接口的时候能够自动返回上面我们定义的ServiceScopeFactory对象,我们依然和上面一样创建了一个自定义的Service,并将其命名为ServiceScopeFactoryService。与ServiceProviderService一样,ServiceScopeFactoryService同时也是一个ServiceCallSite,在Build和Invoke方法中它会返回一个ServiceScopeFactory对象。为了让这个它能够生效,我们依然在ServiceTable初始化的时自动添加一个相应的ServiceEntry。
internal class ServiceScopeFactoryService : IService, IServiceCallSite { public ServiceLifetime Lifetime => ServiceLifetime.Scoped; public IService Next { get; set; } public IServiceCallSite CreateCallSite (ServiceProvider provider, ISet<Type> callSiteChain) { return this; } public Expression Build (Expression provider) { return Expression.New (typeof (ServiceScopeFactory).GetConstructors ().Single (), provider); } public object Invoke (ServiceProvider provider) { return new ServiceScopeFactory (provider); } } internal class ServiceTable { public ServiceTable (IServiceCollection services) { //解析ServiceCollection并添加相应ServiceEntry this.ServieEntries[typeof (IServiceProvider)] = new ServiceEntry (new ServiceProviderService ()); this.ServieEntries[typeof (IServiceScopeFactory)] = new ServiceEntry (new ServiceScopeFactoryService ()); } }
三、提供一组服务的集合
到目前为止,我们自定义的ServiceProvider尚不具备原生ServiceProvider的一项特性,那就是当调用GetService方法时将服务类型指定为IEnumerable<T>或者直接调用扩展方法GetServices时,得到的是一个服务实例的集合。这个特性可以通过一个自定义的ServiceCallSite来完成,我们将其命名为EnumerableCallSite。
internal class EnumerableCallSite : IServiceCallSite { public Type ElementType { get; private set; } public IServiceCallSite[] ServiceCallSites { get; private set; } public EnumerableCallSite (Type elementType, IServiceCallSite[] serviceCallSites) { this.ElementType = elementType; this.ServiceCallSites = serviceCallSites; } public Expression Build (Expression provider) { return Expression.NewArrayInit (this.ElementType, this.ServiceCallSites.Select ( it => Expression.Convert (it.Build (provider), this.ElementType))); } public object Invoke (ServiceProvider provider) { var array = Array.CreateInstance (this.ElementType, this.ServiceCallSites.Length); for (var index = 0; index < this.ServiceCallSites.Length; index++) { array.SetValue (this.ServiceCallSites[index].Invoke (provider), index); } return array; } }
如上面的代码片段所示,EnumerableCallSite具有两个两个只读属性(ElementType和ServiceCallSites),前者表示返回的服务集合的元素类型,后者则返回一组用于提供集合元素的ServiceCallSite。在Invoke和Build方法中,我们只需要根据元素类型创建一个数组,并利用这组ServiceCallSite创建所有的元素即可。这个EnumerableCallSite最终按照如下的方式应用到ServiceProvider的GetServiceCallSite方法中。
internal class ServiceProvider : IServiceProvider, IDisposable { public IServiceCallSite GetServiceCallSite (Type serviceType, ISet<Type> callSiteChain) { try { if (callSiteChain.Contains (serviceType)) { throw new InvalidOperationException (string.Format ("A circular dependency was detected for the service of type '{0}'", serviceType.FullName); } callSiteChain.Add (serviceType); ServiceEntry serviceEntry; if (this.ServiceTable.ServieEntries.TryGetValue (serviceType, out serviceEntry)) { return serviceEntry.Last.CreateCallSite (this, callSiteChain); } if (serviceType.IsGenericType && serviceType.GetGenericTypeDefinition () == typeof (IEnumerable<>)) { Type elementType = serviceType.GetGenericArguments () [0]; IServiceCallSite[] serviceCallSites = this.ServiceTable.ServieEntries.TryGetValue (elementType, out serviceEntry) ? serviceEntry.All.Select (it => it.CreateCallSite (this, callSiteChain)).ToArray () : new IServiceCallSite[0]; return new EnumerableCallSite (elementType, serviceCallSites); } return null; } finally { callSiteChain.Remove (serviceType); } } //其他成员 } }
原文来自:https://www.cnblogs.com/artech/