·您现在的位置: 云翼网络 >> 文章中心 >> 网站建设 >> 网站建设开发 >> 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)
[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));