AddSingleton - 生命周期 - 类是否需要实现 IDisposable?

use*_*601 3 c# garbage-collection dependency-injection asp.net-core

当使用 DI 来添加使用AddScoped或 的服务时AddSingleton,该服务是否需要实现IDisposable(即使它不使用任何非托管资源(例如文件))?

从 Microsoft Docs 找到以下示例:

// Services that implement IDisposable:
public class Service1 : IDisposable {}
public class Service2 : IDisposable {}
public class Service3 : IDisposable {}

public interface ISomeService {}
public class SomeServiceImplementation : ISomeService, IDisposable {}

public void ConfigureServices(IServiceCollection services)
{
    // The container creates the following instances and disposes them automatically:
       services.AddScoped<Service1>();
       services.AddSingleton<Service2>();
       services.AddSingleton<ISomeService>(sp => new SomeServiceImplementation());

    // The container doesn't create the following instances, so it doesn't dispose of
    // the instances automatically:
       services.AddSingleton<Service3>(new Service3());
       services.AddSingleton(new Service3());
}
Run Code Online (Sandbox Code Playgroud)

如果我有这个代码会发生什么:

public class Service0  // (doesn't implement Disposable) 

services.AddScoped<Service0>();   // what happens to it when request scope ends? Does it stay on the heap?

services.AddSingleton<Service0>();   // it lives till application dies
services.AddSingleton(new Service0());  // ??
services.AddSingleton<IConfigureOptions<Service0>>((ctx) =>
   {
          return new ConfigureNamedOptions<Service0>(null, (config) =>
   {
// Do something here -- in debug mode it is executing this logic for each request
}}  // it is returning "new Service0" when a request is made. Does it mean for each request it returns new object and keeps in heap memory or returns same previously created object?
Run Code Online (Sandbox Code Playgroud)

fel*_*x-b 6

该服务是否需要实现 IDisposable(即使它不使用任何非托管资源(例如文件))

通常不会,因为其主要目的IDisposable是允许释放非托管资源。然而,实施还有一个额外的原因IDisposable。该Dispose()方法有时用作完成构造函数中启动的操作的钩子。例如,构造函数启动持续时间测量,同时Dispose()停止测量并向某些监视机制报告持续时间。

关于 IDisposable 的一些背景知识

如果一个对象没有实现IDisposable,并不意味着它保留在堆中。事实上,GC 甚至不知道IDisposable是什么。这个接口只是一个模式。但是,编译器知道,并且它会在语句范围的末尾IDisposable发出调用。Dispose()using

此外,在许多情况下,基础设施层或库(例如 ASP.NET Core 中的 DI)会检查对象是否实现IDisposable,如果实现,则调用Dispose()它。

因此,对象实现IDisposable本身并不能保证它Dispose()会在 GC 之前被调用。这取决于对象的用户。为了真正确保Dispose()在 GC 之前,一次性模式的完整实现包括Dispose()从“析构函数”进行调用。

当请求范围结束时会发生什么?留在堆中?当请求范围结束时会发生什么?

  • AddScoped<Service0>():在请求结束时,对该对象的引用被“遗忘”(GC 可以随时删除它)。在忘记引用之前,会检查该对象是否实现了IDisposable,如果实现了,Dispose()将对其进行调用。

  • AddSingleton<Service0>():在 Web 主机生命周期结束时,对该对象的引用被“遗忘”(GC 可以随时删除它)。在忘记引用之前,会检查该对象是否实现了IDisposable,如果实现了,Dispose()将对其进行调用。

  • AddSingleton(new Service0()):在 Web 主机生命周期结束时,对该对象的引用被“遗忘”(GC 可以随时删除它)。但由于该对象是从外部提供的,并且不是由 DI 实例化的,因此不会检查它IDisposable,也Dispose不会调用它。