详解.NET依赖注入中对象的创建与“销毁”

2025-12-13 0 387

在DI容器中注册类型,DI容器就可以帮我们创建类型的实例;如果注册类型实现了IAsyncDisposable或者IDisposable接口,对象销毁时DI容器还会帮我们调用DisposeAsync或Dispose方法。这是如何实现的呢?一起来看看吧。本文是基于Dependency Injection 8.0编写。如果已熟练使用,可以直接从第三节开始观看。

功能演示#

说明:对象的销毁由GC管理,这里的“销毁”是指调用Dispose方法。

先介绍一下DI容器中类的三种生命周期:Singleton(单例)、Scoped(在每个ServiceProviderEngineScope中只创建一次,可以理解为局部单例)、Transient(每次都创建新对象)。
先定义三个代表生命周期的接口ISingletonService、IScopedService和ITransientService;分别在实现类中打印创建信息和Dispose信息。并且在打印信息里添加了HashCode,可以观察是哪个对象被创建和“销毁”。代码在每个Scope中对每个不同生命周期的类创建2个对象,共12次调用,来看看实际上一共创建了几个对象。


	public interface ISingletonService { }
public interface IScopedService{ }
public interface ITransientService { }

public class SingletonService : ISingletonService, IDisposable
{
  public SingletonService()
  {
    Console.WriteLine($\"{this.GetType()} 被创建了 - {this.GetHashCode()}...\");
  }
  public void Dispose()
  {
    Console.WriteLine($\"{this.GetType()} 被销毁了- {this.GetHashCode()}...\");
  }
}

详解.NET依赖注入中对象的创建与“销毁”

详解.NET依赖注入中对象的创建与“销毁”可以看到,Singleton对象创建了1个,Scoped对象创建了2个(因为有两个ServiceProviderEngineScope),Transient对象每次调用都会创建新的对象,共4个。
Dispose方法调用顺序是,先创建的最后调用。

ASP.NET CORE中Scope#

在ASP.NET CORE中每次请求会创建一个Scope,通过HttpContext.RequestServices可以获取这个Scope对象,所以生命周期为Scoped的类在一次请求中只会创建一次,局部单例。


	// HttpContext.RequestServices
public override IServiceProvider RequestServices
{
  get { return ServiceProvidersFeature.RequestServices; }
  set { ServiceProvidersFeature.RequestServices = value; }
}
public class RequestServicesFeature
{
  public IServiceProvider RequestServices
  {
    get
    {
      if (!_requestServicesSet && _scopeFactory != null)
      {
        _context.Response.RegisterForDisposeAsync(this);
        //每次请求创建一个Scope
        _scope = _scopeFactory.CreateScope();
        _requestServices = _scope.ServiceProvider;
        _requestServicesSet = true;
      }
      return _requestServices!;
    }
    set
    {
      _requestServices = value;
      _requestServicesSet = true;
    }
  }
}

深入理解#

要理解对象的创建和“销毁”,ServiceProvider类是关键。
ServiceProvider创建和“销毁”对象主要是通过它的两个成员来完成的;分别是ServiceProviderEngine _engine和ServiceProviderEngineScope Root

  • ServiceProviderEngine这是一个抽象类,只有一个方法RealizeService,该方法返回一个创建实例的委托。该类不直接创建对象,而是提供一个创建对象的委托!
  • ServiceProviderEngineScope又可以分两类,根scope和子scope,它们的主要功能是:
    捕获创建的对象存入List<object>? _disposables中,用于调用Dispose方法。

ServiceProviderEngine#

通过类型信息创建实例主要有三种办法 1.反射,2.表达式树,3.Emit。这些功能实现在ServiceProviderEngine的子类中,继承关系如下:

  • ServiceProviderEngine

    • RuntimeServiceProviderEngine反射
    • ExpressionsServiceProviderEngine表达式树
    • ILEmitServiceProviderEngineEmit
    • CompiledServiceProviderEngine表达式树和Emit的组合

      • DynamicServiceProviderEngine默认用的这个Engine,实现方式有点难理解

下面看一下这些类的实现


	internal sealed class ExpressionsServiceProviderEngine : ServiceProviderEngine
{
  //使用这个类构建表达式树
  private readonly ExpressionResolverBuilder _expressionResolverBuilder;
  //返回一个创建对象的委托!
  public override Func<ServiceProviderEngineScope, object> RealizeService(ServiceCallSite callSite)
  {
    return _expressionResolverBuilder.Build(callSite);
  }
}
internal sealed class ILEmitServiceProviderEngine : ServiceProviderEngine
{
  //使用这个类构建emit
  private readonly ILEmitResolverBuilder _expressionResolverBuilder;
  public override Func<ServiceProviderEngineScope, object?> RealizeService(ServiceCallSite callSite)
  {
    return _expressionResolverBuilder.Build(callSite);
  }
}
internal sealed class RuntimeServiceProviderEngine : ServiceProviderEngine
{ // 反射
  public static RuntimeServiceProviderEngine Instance { get; } = new RuntimeServiceProviderEngine();
  //使用反射相关方法在CallSiteRuntimeResolver中
  public override Func<ServiceProviderEngineScope, object?> RealizeService(ServiceCallSite callSite)
  {
    return scope => CallSiteRuntimeResolver.Instance.Resolve(callSite, scope);
  }
}
internal abstract class CompiledServiceProviderEngine : ServiceProviderEngine
{
  //通过以下方式选择默认创建实例的方式
#if IL_EMIT
  public ILEmitResolverBuilder ResolverBuilder { get; } //emit构建
#else
  public ExpressionResolverBuilder ResolverBuilder { get; } //表达式树构建
#endif

  public CompiledServiceProviderEngine(ServiceProvider provider)
  {
    ResolverBuilder = new(provider);
  }

  public override Func<ServiceProviderEngineScope, object?> RealizeService(ServiceCallSite callSite) => ResolverBuilder.Build(callSite);
}

默认是使用emit的方式创建对象,通过以下方法可以验证默认使用的引擎和创建实例的方式


	static void EngineInfo(ServiceProvider provider)
{
  var p = Expression.Parameter(typeof(ServiceProvider));
  //相当于 provider._engine
  var lambda = Expression.Lambda<Func<ServiceProvider, object>>(Expression.Field(p, \"_engine\"), p);

  var engine = lambda.Compile()(provider);
  var baseType = engine.GetType().BaseType!;
  // 相当于(provider._engine as CompiledServiceProviderEngine).ResolverBuilder
  var lambda2 = Expression.Lambda<Func<ServiceProvider, object>>(
    Expression.Property(Expression.Convert(Expression.Field(p, \"_engine\"), baseType), \"ResolverBuilder\"), p);

  var builder = lambda2.Compile()(provider);
  Console.WriteLine(engine.GetType());
  Console.WriteLine(builder.GetType());
  //输出信息:
  //Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine
  //Microsoft.Extensions.DependencyInjection.ServiceLookup.ILEmitResolverBuilder
}

从上面输出可以看到DynamicServiceProviderEngine是默认的Engine,并且它的父类CompiledServiceProviderEngine是使用的ILEmitResolverBuilder。
下面来介绍DynamicServiceProviderEngine,这段代码三年前看不懂,我三年后还是不太懂,实现方式有点难以理解,有大佬懂的可以解答下。
首先,Singleton对象是不会调用这个方法的,只有生命周期是Scoped和Transient才会调用这个方法。通过调用RealizeService获取一个创建对象的委托;对于每一个服务标识,在调用2次后,替换为用emit的方式去创建实例的委托(如果不理解服务标识,看我的这篇文章),并且,还是用线程池实现的,对于Web开发,而CPU绑定的异步不推荐使用线程池。
前几次调用,反射性能应该是优于emit和表达式树,因为后两者有一个构建委托的过程。但是,使用线程池的影响应该远大于前者吧。一开始就直接使用emit创建对象不应该优于使用线程池?上百个类使用线程池,会导致网站启动时很卡。当然,也就启动后一小段时间卡。


	internal sealed class DynamicServiceProviderEngine : CompiledServiceProviderEngine
{
  public override Func<ServiceProviderEngineScope, object?> RealizeService(ServiceCallSite callSite)
  {
    int callCount = 0;
    return scope =>
    {
      // Resolve the result before we increment the call count, this ensures that singletons
      // won\'t cause any side effects during the compilation of the resolve function.
      var result = CallSiteRuntimeResolver.Instance.Resolve(callSite, scope);
      if (Interlocked.Increment(ref callCount) == 2)
      {
        //不捕获ExecutionContext,AsyncLocal失效。
        _ = ThreadPool.UnsafeQueueUserWorkItem(_ =>
        {
          _serviceProvider.ReplaceServiceAccessor(callSite, base.RealizeService(callSite));
        },
        null);
      }
      return result;
    };
  }
}

获取创建对象的委托时,需要传入参数ServiceCallSite,callSite对象有类型的创建信息,指明如何创建这个类型的实例,比如通过构造函数、工厂、创建数组(IEnumerable<>服务)、常量等创建实例。并且在后面调用创建对象的委托时,如果需要缓存,会把创建出来的对象缓存到callSite对象中。

ServiceProviderEngineScope#

下面再来介绍下ServiceProviderEngineScope,主要成员及相关介绍在下面代码中。
如何创建ServiceProviderEngineScope对象呢?通过services.CreateScope()就是创建一个scope对象。创建scope对象时,会传递ServiceProvider并保存到RootProvider属性中。而每个scope对象又有一个名字为ServiceProvider的属性,它的值是this;所以scope.ServiceProvider == scope。
我们发现这个对象也有GetService方法,发现它只是转发了一下,其实还是调用ServiceProvider的GetService获取对象。这个方法还把当前scope作为参数传递过去了,表示创建出来的对象由当前scope对象管理。
我们通过scope.ServiceProvider.GetService<ISingletonService>()获取对象和services.GetService<ISingletonService>()基本一样,只是传递的scope不同,前者是传递自己,后者是传递ServiceProvider对象中的scope对象(也就是Root属性)。
再次说明:scope.ServiceProvider是返回自己,scope.RootProvider才是真正的ServiceProvider对象


	internal sealed class ServiceProviderEngineScope : IServiceScope, IServiceProvider, IKeyedServiceProvider, IAsyncDisposable, IServiceScopeFactory
{
  //缓存创建出来的对象,只会缓存“非根Scope”创建的且生命周期为“Scoped”的实例
  internal Dictionary<ServiceCacheKey, object?> ResolvedServices { get; }
  // 存放捕获的 disposables 对象
  private List<object>? _disposables;
  //是否为根Scope
  public bool IsRootScope { get; }
  //这里有点绕,ServiceProvider属性返回的是自己。每个子Scope就是 engineScope
  public IServiceProvider ServiceProvider => this;
  //RootProvider属性是保存的ServiceProvider对象
  internal ServiceProvider RootProvider { get; }
  //所有创建Scope的方法都是调用 ServiceProvider的CreateScope方法
  public IServiceScope CreateScope() => RootProvider.CreateScope();
  //唯一构造函数
  public ServiceProviderEngineScope(ServiceProvider provider, bool isRootScope)
  {
    ResolvedServices = new Dictionary<ServiceCacheKey, object?>();
    RootProvider = provider; //保存ServiceProvider对象
    IsRootScope = isRootScope;//只有ServiceProvider对象中的scope对象的这个值是true,其它都是false
  }
  public object? GetService(Type serviceType)
  {
    //每个子scope还是调用RootProvider创建服务,只是由子scope捕获对象用于释放Dispose
    return RootProvider.GetService(ServiceIdentifier.FromServiceType(serviceType), this);
  }
}

在ServiceProvider的构造函数中,注册了IServiceProvider和IServiceScopeFactory服务。两者都是返回一个ServiceProviderEngineScope对象,前者是返回当前scope对象,后者是返回单例根scope对象(Root属性)。这是理解创建scope对象流程的前提。

调用services.CreateScope()创建scope对象流程:

  • 1.调用ServiceProvider的CreateScope方法。services.CreateScope()
  • 2.CreateScope方法就是获取根scope并调用它自己的CreateScope方法。provider.GetRequiredService<IServiceScopeFactory>().CreateScope()
  • 3.而根scope的CreateScope方法是调用ServiceProvider的CreateScope方法。RootProvider.CreateScope()
  • 4.在ServiceProvider的CreateScope方法中就是new一个对象。new ServiceProviderEngineScope(this, isRootScope: false)

兜兜转转,services.CreateScope()最终是调用自己内部方法CreateScope。代码和注释已贴出,结合上下两段代码看。


	//这是在ServiceProvider的构造函数中注册的服务
CallSiteFactory.Add(ServiceIdentifier.FromServiceType(typeof(IServiceProvider)), new ServiceProviderCallSite());
CallSiteFactory.Add(ServiceIdentifier.FromServiceType(typeof(IServiceScopeFactory)), new ConstantCallSite(typeof(IServiceScopeFactory), Root));

//我们创建Scope是调用的这个扩展方法,结合上面代码,你会发现CreateScope其实是调用的自己的同名方法
public static IServiceScope CreateScope(this IServiceProvider provider)
{
  return provider.GetRequiredService<IServiceScopeFactory>().CreateScope();
}
//这里是ServiceProvider的CreateScope方法,它“internal”修饰的,但最终调用的这里
internal IServiceScope CreateScope()
{
  // 创建Scope最终是调用的这里,ServiceProvider会保存在每个Scope里,每个Scope都是同一个ServiceProvider
  return new ServiceProviderEngineScope(this, isRootScope: false);
}根scope和子scope# 

根scope和子scope通过IsRootScope属性区分,保存在ServiceProvider中的Root属性就是一个根scope,其生命周期是全局的,程序停止才会调用Dispose方法。ASP.NET CORE中每次请求创建的scope就是一个子scope。通过两个例子加深印象:


	static void EngineScopeTest()
{
  using var services = new ServiceCollection().BuildServiceProvider();
  using var scope1 = services.CreateScope();
  using var scope2 = scope1.ServiceProvider.CreateScope();
  //返回当前scope
  var rootScope = services.GetService<IServiceProvider>();
  //返回根scope
  var rootScope2 = services.GetService<IServiceScopeFactory>();

  var currentScope = scope1.ServiceProvider.GetService<IServiceProvider>();
  var rootScope3 = scope1.ServiceProvider.GetService<IServiceScopeFactory>();

  var currentScope2 = scope2.ServiceProvider.GetService<IServiceProvider>();
  var rootScope4 = scope2.ServiceProvider.GetService<IServiceScopeFactory>();
  // 获取根scope
  var root = GetRoot(services);
  //运行代码输出4个 True
  Console.WriteLine(rootScope == root && rootScope == (root as IServiceScope)!.ServiceProvider);
  Console.WriteLine(rootScope == rootScope3 && rootScope == rootScope4);
  Console.WriteLine(currentScope == scope1 && currentScope == scope1.ServiceProvider);
  Console.WriteLine(currentScope2 == scope2 && currentScope2 == scope2.ServiceProvider);
}
static object GetRoot(ServiceProvider provider)
{ //通过表达式树获取根scope
  var p = Expression.Parameter(typeof(ServiceProvider));
  //相当于 provider.Root
  var lambda = Expression.Lambda<Func<ServiceProvider, object>>(Expression.Property(p, \"Root\"), p);
  return lambda.Compile()(provider);
}详解.NET依赖注入中对象的创建与“销毁” 

详解.NET依赖注入中对象的创建与“销毁”

调用GetService<IServiceProvider>()返回的是当前scope,调用GetService<IServiceScopeFactory>()返回的是根scope。就算通过子scope方法scope1.ServiceProvider.CreateScope()创建scope,最终还是调用new ServiceProviderEngineScope(this, isRootScope: false)创建scope,并且子scope之间没有层级关系,每个子scope都保存了同一份ServiceProvider对象。
再通过以下例子验证一下,子scope是否真的保存了ServiceProvider对象


	static void EngineScopeWhitServiceProviderTest()
{
  using var services = new ServiceCollection().BuildServiceProvider();
  using var scope1 = services.CreateScope()!;
  using var scope2 = scope1.ServiceProvider.CreateScope()!;

  var rootScope = services.GetService<IServiceProvider>();

  var currentScope = scope1.ServiceProvider.GetService<IServiceProvider>();

  var currentScope2 = scope2.ServiceProvider.GetService<IServiceProvider>();

  var provider = GetRootProvider(scope1);//获取子scope保存的ServiceProvider
  var provider2 = GetRootProvider(scope2);//获取子scope保存的ServiceProvider
  //获取根scope的ServiceProvider
  var root = (IServiceScope)GetRoot(services);
  var provider3 = GetRootProvider(root);

  Console.WriteLine(services == provider && services == provider2 && services == provider3);
  Console.WriteLine(services != rootScope && services != currentScope && services != root.ServiceProvider);
}

static object GetRootProvider(IServiceScope scope)
{ //通过表达式树获取RootProvider
  var p = Expression.Parameter(typeof(IServiceScope));
  //相当于 scope.RootProvider
  var lambda = Expression.Lambda<Func<IServiceScope, object>>(
   Expression.Property(Expression.Convert(p, scope.GetType()), \"RootProvider\"), p);
  return lambda.Compile()(scope);
}详解.NET依赖注入中对象的创建与“销毁” 

详解.NET依赖注入中对象的创建与“销毁”

验证没问题。根scope和子scope的几个特点:

  • 都会捕获需要释放Dispose的对象
  • 所有Singleton对象的“销毁”由根scope管理
  • 对于Scoped和Transient的对象,谁关联谁管理(创建对象时需要传入一个关联scope对象)

    • 注意:对于Scoped和Transient的对象被ServiceProvider创建时,它们的生命周期就变成了Singleton,它们的Dispose方法往往需要等程序停止时才会调用。虽然可以在创建容器时设置参数ValidateScopes开启校验,但只会校验Scoped对象,它只会禁止ServiceProvider中创建Scoped对象和Singleton对象中注入Scoped对象,对于Transient对象不会校验,所以Transient对象的Dispose方法要等程序停止时才会调用。
  • 子scope会缓存生命周期为“Scoped”的实例,并保存到ResolvedServices属性中。

    • 虽然后面会把创建对象的委托替换成了Emit的形式,但是生命周期为“Scoped”的实例已经保存到ResolvedServices属性中,所以后面创建的“Scoped”的实例还是同一个。
  • 对于根scope关联的Singleton和Scoped对象,创建出来后都会缓存,只是保存在不同地方(创建对象的委托中或ServiceCallSite中)。

问:子scope创建的Singleton对象是由根scope管理的,那子scope是怎样获取根scope对象的呢?
答:前面讲过,子scope会保存ServiceProvider对象,访问它的Root属性就可以得到根scope。像这样scope1.RootProvider.Root。这两个成员的修饰符都是internal,我们要想访问,可以参考前面的代码GetRootProvider和GetRoot

Dispose#

对象被DI容器创建出来,如果有实现Dispose接口,就会被ServiceProviderEngineScope捕获并放入对象List<object>? _disposables中,并在DI容器本身被调用Dispose方法时,会逆序调用_disposables中每个对象的Dispose方法(for (int i = _disposables.Count – 1; i >= 0; i–)),也就是调用scope的Dispose方法就会调用它捕获对象的Dispose方法。

scope的Dispose方法调用的时机:

  • 对于根scope,也就是ServiceProvider的Root属性,当ServiceProvider的Dispose方法被调用时,会调用Root.Dispose()
  • 对于子scope需要自己手动调用Dispose方法或者用using。

通过一段代码来验证一下scope对象是否真的捕获了对象:


	static void DisposeTest()
{
  using var services = new ServiceCollection()
    .AddSingleton<ISingletonService, SingletonService2>()
    .AddScoped<IScopedService, ScopedService2>()
    .AddTransient<ITransientService, TransientService2>()
    .BuildServiceProvider();
 
  var singleton1 = services.GetService<ISingletonService>();
  var scoped1 = services.GetService<IScopedService>();
  var transient1 = services.GetService<ITransientService>();
  //获取被捕获的对象
  var rootDisposables = GetRootDisposables(services);

  Console.WriteLine(rootDisposables.Any(o => o == singleton1)
    && rootDisposables.Any(o => o == scoped1)
    && rootDisposables.Any(o => o == transient1)
    && rootDisposables.Count == 3);

  using (var scope1 = services.CreateScope())
  {
    var singleton2 = scope1.ServiceProvider.GetService<ISingletonService>();
    var scoped2 = scope1.ServiceProvider.GetService<IScopedService>();
    var transient2 = scope1.ServiceProvider.GetService<ITransientService>();

    var singleton3 = scope1.ServiceProvider.GetService<ISingletonService>();
    var scoped3 = scope1.ServiceProvider.GetService<IScopedService>();
    var transient3 = scope1.ServiceProvider.GetService<ITransientService>();
    //获取被捕获的对象
    var scopeDisposables = GetScopeDisposables(scope1.ServiceProvider);
    //Singleton保存在Root Scope中
    Console.WriteLine(scopeDisposables.Any(o => o == singleton2) == false
      && scopeDisposables.Any(o => o == singleton3) == false
      && scopeDisposables.Count == 3);//2个Transient对象,1个Scope对象

    Console.WriteLine(scopeDisposables.Any(o => o == scoped2)
      && scopeDisposables.Any(o => o == transient2)
      && scopeDisposables.Any(o => o == scoped3)
      && scopeDisposables.Any(o => o == transient3));
  }
}
static List<object> GetRootDisposables(ServiceProvider provider)
{
  var providerParam = Expression.Parameter(typeof(ServiceProvider));
  // provider.Root
  var engineParam = Expression.Property(providerParam, \"Root\");
  // provider.Root._disposables;
  var dispoParam = Expression.Field(engineParam, \"_disposables\");
  var lambda = Expression.Lambda<Func<ServiceProvider, List<object>>>(dispoParam, providerParam);

  return lambda.Compile()(provider);
}
static List<object> GetScopeDisposables(IServiceProvider provider)
{
  //这个provider就是ServiceProviderEngineScope
  var providerParam = Expression.Parameter(typeof(IServiceProvider));
  // provider as ServiceProviderEngineScope
  var engineParam = Expression.Convert(providerParam, provider.GetType());
  // (provider as ServiceProviderEngineScope)._disposables;
  var dispoParam = Expression.Field(engineParam, \"_disposables\");
  var lambda = Expression.Lambda<Func<IServiceProvider, List<object>>>(dispoParam, providerParam);

  return lambda.Compile()(provider);
}详解.NET依赖注入中对象的创建与“销毁” 

输出3个True,没问题。
详解.NET依赖注入中对象的创建与“销毁”

ServiceProvider#

最后再介绍一下,ServiceProvider是如何利用ServiceProviderEngineScope和ServiceProviderEngine创建和管理对象的。类ServiceIdentifier是DI8.0的新功能


	private sealed class ServiceAccessor
{
  //类型的创建信息和缓存
  public ServiceCallSite? CallSite { get; set; }
  //来自ServiceProviderEngine的RealizeService方法
  public Func<ServiceProviderEngineScope, object?>? RealizedService { get; set; }
}
//注意,RealizeService方法的参数和返回值就是ServiceAccessor类的成员
internal sealed class ILEmitServiceProviderEngine : ServiceProviderEngine
{
  public override Func<ServiceProviderEngineScope, object?> RealizeService(ServiceCallSite callSite)
  {
   //...
  }
}
public sealed class ServiceProvider : IServiceProvider, IKeyedServiceProvider, IDisposable, IAsyncDisposable
{
  //伪代码,但最终是new DynamicServiceProviderEngine
  internal ServiceProviderEngine _engine = new DynamicServiceProviderEngine(this);
  //根scope 它的IsRootScope属性为true
  internal ServiceProviderEngineScope Root { get; }

  //我们获取服务最终都是调用这里
  internal object? GetService(ServiceIdentifier serviceIdentifier, ServiceProviderEngineScope serviceProviderEngineScope)
  {
    //_serviceAccessors是一个字典,可以理解为每一个服务标识对应一个创建对象的创建对象的委托
    ServiceAccessor serviceAccessor = _serviceAccessors.GetOrAdd(serviceIdentifier, CreateServiceAccessor);
    //调用 委托 获取对象
    object? result = serviceAccessor.RealizedService?.Invoke(serviceProviderEngineScope);

    return result;
  }

  private ServiceAccessor CreateServiceAccessor(ServiceIdentifier serviceIdentifier)
  {
    //GetCallSite方法获取类型的创建信息,指明如何创建这个类型的实例,比如通过构造函数、工厂、创建数组(IEnumerable<>服务)、常量等创建实例
    ServiceCallSite? callSite = CallSiteFactory.GetCallSite(serviceIdentifier, new CallSiteChain());

    if (callSite.Cache.Location == CallSiteResultCacheLocation.Root)
    {
      //Singleton对象,通过反射创建一次
      object? value = CallSiteRuntimeResolver.Instance.Resolve(callSite, Root);
      //Resolve方法里,在对象创建出来后会保存到callSite里面,如果实现dispose接口还会被Root捕获
      return new ServiceAccessor { CallSite = callSite, RealizedService = scope => value };
    }
    //调用 ServiceProviderEngine 获取一个 创建对象的委托
    Func<ServiceProviderEngineScope, object?> realizedService = _engine.RealizeService(callSite);
    return new ServiceAccessor { CallSite = callSite, RealizedService = realizedService };
  }
}

代码只保留了核心逻辑。创建对象时,所有的GetService方法最终都是调用这个方法GetService(ServiceIdentifier serviceIdentifier, ServiceProviderEngineScope serviceProviderEngineScope)。该方法接收一个“服务标识”和一个“ServiceProviderEngineScope”对象,如果是通过services.GetService调用,传递的就是根scope;如果是通过scope1.ServiceProvider.GetService调用,传递的就是当前子scope对象。
GetService方法先通过CreateServiceAccessor获取“服务标识”相关信息(ServiceCallSite)和创建对象的委托。ServiceCallSite前面有介绍。Singleton对象不会通过ServiceProviderEngine的RealizeService方法获取创建对象的委托,而是直接通过反射创建对象并缓存起来。Scoped和Transient对象通过_engine.RealizeService(callSite)获取创建对象的委托。最后就是调用委托获取对象。

总结#

.NET依赖注入中获取对象就是通过GetService方法,方法内容主要就两步:

  • 1.获取创建对象的委托(通过ServiceProviderEngine)
  • 2.调用委托创建对象

如果创建出来的对象实现了IAsyncDisposable或者IDisposable接口,创建出来的对象会被ServiceProviderEngineScope捕获用于调用Dispose方法。
如有疑问,欢迎评论交流。如有错误,欢迎批评指出。

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

申明:本文由第三方发布,内容仅代表作者观点,与本网站无关。对本文以及其中全部或者部分内容的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。本网发布或转载文章出于传递更多信息之目的,并不意味着赞同其观点或证实其描述,也不代表本网对其真实性负责。

左子网 编程相关 详解.NET依赖注入中对象的创建与“销毁” https://www.zuozi.net/36479.html

常见问题
  • 1、自动:拍下后,点击(下载)链接即可下载;2、手动:拍下后,联系卖家发放即可或者联系官方找开发者发货。
查看详情
  • 1、源码默认交易周期:手动发货商品为1-3天,并且用户付款金额将会进入平台担保直到交易完成或者3-7天即可发放,如遇纠纷无限期延长收款金额直至纠纷解决或者退款!;
查看详情
  • 1、描述:源码描述(含标题)与实际源码不一致的(例:货不对板); 2、演示:有演示站时,与实际源码小于95%一致的(但描述中有”不保证完全一样、有变化的可能性”类似显著声明的除外); 3、发货:不发货可无理由退款; 4、安装:免费提供安装服务的源码但卖家不履行的; 5、收费:价格虚标,额外收取其他费用的(但描述中有显著声明或双方交易前有商定的除外); 6、其他:如质量方面的硬性常规问题BUG等。 注:经核实符合上述任一,均支持退款,但卖家予以积极解决问题则除外。
查看详情
  • 1、左子会对双方交易的过程及交易商品的快照进行永久存档,以确保交易的真实、有效、安全! 2、左子无法对如“永久包更新”、“永久技术支持”等类似交易之后的商家承诺做担保,请买家自行鉴别; 3、在源码同时有网站演示与图片演示,且站演与图演不一致时,默认按图演作为纠纷评判依据(特别声明或有商定除外); 4、在没有”无任何正当退款依据”的前提下,商品写有”一旦售出,概不支持退款”等类似的声明,视为无效声明; 5、在未拍下前,双方在QQ上所商定的交易内容,亦可成为纠纷评判依据(商定与描述冲突时,商定为准); 6、因聊天记录可作为纠纷评判依据,故双方联系时,只与对方在左子上所留的QQ、手机号沟通,以防对方不承认自我承诺。 7、虽然交易产生纠纷的几率很小,但一定要保留如聊天记录、手机短信等这样的重要信息,以防产生纠纷时便于左子介入快速处理。
查看详情

相关文章

猜你喜欢
发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务