当前位置: 移动技术网 > IT编程>开发语言>.net > Core官方DI解析(4)--CallSiteRuntimeResolver

Core官方DI解析(4)--CallSiteRuntimeResolver

2018年11月29日  | 移动技术网IT编程  | 我要评论
​ 类型是一个创建或获取服务实例的类型,这个类型继承了 这个类型,也是使用了访问者模式,下面一一来解析此类 ServiceProviderEngineScope 在解析 之前先看一下 类型,这个类型就可以是一个容器类型,最后实例化的服务对象就缓存在此类之中, 从下面代码中可以看出此类实现了 和`IS ...

callsiteruntimeresolver类型是一个创建或获取服务实例的类型,这个类型继承了callsitevisitor<targument, tresult>这个类型,也是使用了访问者模式,下面一一来解析此类

serviceproviderenginescope

在解析`callsiteruntimeresolver`之前先看一下`serviceproviderenginescope`类型,这个类型就可以是一个容器类型,最后实例化的服务对象就缓存在此类之中,

从下面代码中可以看出此类实现了`iservicescope`和`iserviceprovider`两个接口,并且此类型拥有两个字段

_disposables:idisposabl集合,此字段缓存的时所有实现了idisposable接口的注册服务,以便在释放此容器实例时并将这些服务一起释放

_disposed:判断此属性是否已被是否释放

internal class serviceproviderenginescope : iservicescope, iserviceprovider
{
       private list<idisposable> _disposables;
       private bool _disposed;
}
在此类中还具有两个属性,一个是缓存实例对象的集合和一个**serviceproviderengine**类型的属性,从下面可以看出缓存集合使用了是`servicecachekey`作为缓存的key,

而engine是引擎类型,此属性通过构造函数传入,并且所有容器共享一个`serviceproviderengine`,也就是共享容器共享注册的服务   
//    缓存的实例对象集合
internal dictionary<servicecachekey, object> resolvedservices { get; } = new dictionary<servicecachekey, object>();
//    所有serviceproviderenginescope对象共享一个serviceproviderengine
public serviceproviderengine engine { get; }

//   构造函数
 public serviceproviderenginescope(serviceproviderengine engine)=> engine = engine;
这个类中一共具有四个方法,
  • getservice():获取对象,可以看到此方法调用的enginegetservice(),这个方法到serviceproviderengine时再看
  • serviceprovider():这个方法返回的是当前对象
  • dispose():释放当前容器,可以看到在释放当前容器时会把**_disposables集合中所有实例进行释放,并把_disposed**属性设置true
  • capturedisposable():这个方法缓存要被的释放的服务实例
public object getservice(type servicetype)
{
     if (_disposed)
          //        如果已被释放,就不能调用此方法
          throwhelper.throwobjectdisposedexception();
     return engine.getservice(servicetype, this);
}

public iserviceprovider serviceprovider => this;

public void dispose()
{
     lock (resolvedservices)
     {
          if (_disposed)
               return;
          _disposed = true;
          if (_disposables != null)
          {
               for (var i = _disposables.count - 1; i >= 0; i--)
               {
                    var disposable = _disposables[i];
                    disposable.dispose();
               }

               _disposables.clear();
          }

          resolvedservices.clear();
     }
}
//  缓存所有需要清理的服务实例
internal object capturedisposable(object service)
{

     if (!referenceequals(this, service))
     {
          if (service is idisposable disposable)
          {
               lock (resolvedservices)
               {
                    if (_disposables == null)
                         _disposables = new list<idisposable>();
                    _disposables.add(disposable);
               }
          }
     }
     return service;
}

callsiteruntimeresolver

​ 上面说过callsiteruntimeresolver这个类型是创建和获取服务实例类型的访问者,这个类型泛型参数分别为runtimeresolvercontext类型和实例对象类型object

internal sealed class callsiteruntimeresolver : callsitevisitor<runtimeresolvercontext, object>{}

runtimeresolvercontext类型是一个serviceproviderenginescope封装类型,这个类型中具有一个serviceproviderenginescope类型属性和一个runtimeresolverlock枚举类型属性,这个枚举类型在实例化对象时当做了锁使用

internal struct runtimeresolvercontext
{
     public serviceproviderenginescope scope { get; set; }
     //     锁
     public runtimeresolverlock acquiredlocks { get; set; }
}
[flags]
internal enum runtimeresolverlock
{
     scope = 1,
     root = 2
}

callsiteruntimeresolver类型中拥有两类方法,

  • 根据注册服务的生命周期进行访问服务实例对象
  • 根据servicecallsite的设置类型进行访问服务实例对象

这两个类都在其callsitevisitor<targument, tresult>基类中

//      根据服务对象的生命周期进行访问访问实例
protected virtual tresult visitcallsite(servicecallsite callsite, targument argument)
{
     // 缓存位置由servicecallsite内部的cache属性的location提供
     switch (callsite.cache.location)
     {
          case callsiteresultcachelocation.root:
               return visitrootcache(callsite, argument);
          case callsiteresultcachelocation.scope:
               return visitscopecache(callsite, argument);
          case callsiteresultcachelocation.dispose:
               return visitdisposecache(callsite, argument);
          case callsiteresultcachelocation.none:
               return visitnocache(callsite, argument);
          default:
               throw new argumentoutofrangeexception();
     }
}

//      根据其servicecallsite的kind属性访问服务对象
protected virtual tresult visitcallsitemain(servicecallsite callsite, targument argument)
{
     switch (callsite.kind)
     {
          case callsitekind.factory:
               return visitfactory((factorycallsite)callsite, argument);
          case  callsitekind.ienumerable:
               return visitienumerable((ienumerablecallsite)callsite, argument);
          case callsitekind.constructor:
               return visitconstructor((constructorcallsite)callsite, argument);
          case callsitekind.constant:
               return visitconstant((constantcallsite)callsite, argument);
          case callsitekind.serviceprovider:
               return visitserviceprovider((serviceprovidercallsite)callsite, argument);
          case callsitekind.servicescopefactory:
               return visitservicescopefactory((servicescopefactorycallsite)callsite, argument);
          default:
               throw new notsupportedexception($"call site type {callsite.gettype()} is not supported");
     }
}

​这两个方法内部调用的方法部分被callsiteruntimeresolver类中重写,

下面先来看看根据生命周期进行访问的一系列方法

  • vistrootcache:

    这个方法是访问root生命周期的方法,可以看到这个在这个方法调用了一个visitcache(),这个方法一共四个参数,第一个,第二个分别是当前方法函数。第三个参数代表容器对象,容器使用的是serviceproviderengine实例中的root属性,这个容器代表了顶级容器,这也就是root生命周期的本质,使用的顶级容器进行创建/获取实例,第四个参数锁,此方法使用的是runtimeresolverlock.root

  • visitscopecache:

    这个方法是访问scoped生命周期方法,此方法和上面方法相似,也是调用了visitcache(),但是不同的是是锁不同,这个锁是根据当前容器来决定,如果当前容器为顶级容器,就使用root锁,所以不为顶级容器,则使用scope

  • visitdisposecache

    这个方法访问transient生命周期方法,可以看到这个方法直接调用visitcallsitemain()进行获取实例对象,然后调用capturedisposable()将此对象尝试缓存到serviceproviderenginescope容器的**_disposables**集合中

  • visitnocache

    这个方法代表不缓存,这个方法在callsiteruntimeresolver类中未重写,所以直接调用的callsitevisitor类型的visitnocache(),也基类中直接调用visitcallsitemain()

////        callsiteruntimeresolver
//      访问root生命周期方法
protected override object visitrootcache(servicecallsite singletoncallsite, runtimeresolvercontext context)
      => visitcache(singletoncallsite, context, context.scope.engine.root, runtimeresolverlock.root);
//      访问scoped生命周期方法
protected override object visitscopecache(servicecallsite singletoncallsite, runtimeresolvercontext context)
{
     //      如果当前容器为根容器,则将其锁转换为root,否则为scope
     var requiredscope = context.scope == context.scope.engine.root ?
          runtimeresolverlock.root :
     runtimeresolverlock.scope;
     return visitcache(singletoncallsite, context, context.scope, requiredscope);
}
//      访问transient生命周期方法
protected override object visitdisposecache(servicecallsite transientcallsite, runtimeresolvercontext context)
      => context.scope.capturedisposable(visitcallsitemain(transientcallsite, context));

////        callsitevisitor
//      无缓存
 protected virtual tresult visitnocache(servicecallsite callsite, targument argument)
      => visitcallsitemain(callsite, argument);
**visitcache()**这个方法是使用指定的容器进行实例化并缓存服务实例对象,在下面代码中可以看到,代码中根据**runtimeresolvercontext**实例的枚举值与第四个参数进行,如果不相同,则进行加锁。然后进行获取实例服务对象,如果已缓存则直接获取,没有缓存则调用**visitcallsitemain()**获取实例并缓存
private object visitcache(servicecallsite scopedcallsite, runtimeresolvercontext context, serviceproviderenginescope serviceproviderengine, runtimeresolverlock locktype)
{
     bool locktaken = false;
     //      获取容器中的缓存服务实例属性
     var resolvedservices = serviceproviderengine.resolvedservices;
     if ((context.acquiredlocks & locktype) == 0)
         //      如果当前枚举值与runtimeresolvercontext的枚举值不相同,则加锁
          monitor.enter(resolvedservices, ref locktaken);
     try
     {
          //      如果当前数据并未在缓存之中,则实例化此对象并将其缓存至集合中
          if (!resolvedservices.trygetvalue(scopedcallsite.cache.key, out var resolved))
          {
               //      获取实例对象
               resolved = visitcallsitemain(scopedcallsite, new runtimeresolvercontext
                                            {
                                                 scope = serviceproviderengine,
                                                 acquiredlocks = context.acquiredlocks | locktype
                                            });
               //      将当前对象尝试加入到容器的_disposables集合
               serviceproviderengine.capturedisposable(resolved);
               //      缓存实例对象
               resolvedservices.add(scopedcallsite.cache.key, resolved);
          }
          return resolved;
     }
     finally
     {
          if (locktaken)
            monitor.exit(resolvedservices);
     }
}
**visitcallsitemain()**内调用的所有方法都在`callsiteruntimeresolver`类进行了重写,下面看看`callsiteruntimeresolve`类中的这些方法
  • visitfactory

    visitfactory()中直接调用了factorycallsite实例对象的工厂方法获取实例

  • visitienumerable

    visitienumerable()中实例了ienumerablecallsiteservicecallsites集合的所有对象,并组装到一个数组进行返回

  • constructorcallsite

    visitconstructor()中使用反射方法实例化对象,并且如果构造函数不为空则获取所有参数的实例对象

  • constantcallsite

    visitconstant()中直接返回了constantcallsite中的对象

  • visitserviceprovider

    visitserviceprovider()直接返回了runtimeresolvercontext封装的容器

  • visitservicescopefactory

    visitservicescopefactory()中则直接返回了容器实例中引擎对象(serviceproviderengine)

//      factorycallsite
protected override object visitfactory(factorycallsite factorycallsite, runtimeresolvercontext context)
     //     调用工厂方法进行实例化
     => factorycallsite.factory(context.scope);

//      ienumerablecallsite
protected override object visitienumerable(ienumerablecallsite enumerablecallsite, runtimeresolvercontext context)
{
     var array = array.createinstance(
          enumerablecallsite.itemtype,
          enumerablecallsite.servicecallsites.length);
     for (var index = 0; index < enumerablecallsite.servicecallsites.length; index++)
     {
          //        实例化ienumerablecallsite.servicecallsites中所有的服务实例对象并赋值到数组中
          var value = visitcallsite(enumerablecallsite.servicecallsites[index], context);
          array.setvalue(value, index);
     }
     return array;
}

//      constructorcallsite
protected override object visitconstructor(constructorcallsite constructorcallsite, runtimeresolvercontext context)
{
     object[] parametervalues;
     if (constructorcallsite.parametercallsites.length == 0)
          parametervalues = array.empty<object>();
     else
     {
          //        如果当前构造器参数不为空,则实例化每一个参数的实例对象
          parametervalues = new object[constructorcallsite.parametercallsites.length];
          for (var index = 0; index < parametervalues.length; index++)
               parametervalues[index] = visitcallsite(constructorcallsite.parametercallsites[index], context);
     }
     try
     {
          //        根据参数对象进行实例化对象并返回
          return constructorcallsite.constructorinfo.invoke(parametervalues);
     }
     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;
     }
}

//      constantcallsite
 protected override object visitconstant(constantcallsite constantcallsite, runtimeresolvercontext context)
      //        直接返回constantcallsite的值
      => constantcallsite.defaultvalue;

//      serviceprovidercallsite
protected override object visitserviceprovider(serviceprovidercallsite serviceprovidercallsite, runtimeresolvercontext context) 
     //     直接返回runtimeresolvercontext封装的容器
     => context.scope;

//      servicescopefactorycallsite
 protected override object visitservicescopefactory(servicescopefactorycallsite servicescopefactorycallsite, runtimeresolvercontext context)
      //        直接返回容器内的serviceproviderengine
      => context.scope.engine;
在`callsiteruntimeresolver`中还有叫做**resolve()**,这个方法则是外部调用的,这个方法是由一个`servicecallsite`对象和一个容器对象`serviceproviderenginescope`,然后直接调用**visitcallsite()**进行方法,可以看到调用此方法时**acquiredlocks**属性并未赋值.
public object resolve(servicecallsite callsite, serviceproviderenginescope scope)
{
     return visitcallsite(callsite, new runtimeresolvercontext
                          {
                               scope = scope
                          });
}

如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网