·您现在的位置: 云翼网络 >> 文章中心 >> 网站建设 >> 网站建设开发 >> ASP.NET网站开发 >> [Asp.net 5] DependencyInjection项目代码分析4-微软的实现(4)

[Asp.net 5] DependencyInjection项目代码分析4-微软的实现(4)

作者:佚名      ASP.NET网站开发编辑:admin      更新时间:2022-07-23

[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));