.NET Core 对象( Transient、Scope、Singleton )生命周期详解 (对象创建以及释放)
首先我们在VS2019中创建一个.NET Core的控制台程序,方便演示;
需要安装两个依赖包
Microsoft.Extensions.DependencyInjection 依赖注入对象的具体实现
Microsoft.Extensions.DependencyInjection.Abstractions 依赖注入对象的抽象
Part 1 : AddTransient AddScoped AddSingleton
话不多说,看以下Demo的代码以及运行结果
public static class Demo { public interface IAccount { } public interface IMessage { } public interface ITool { } public class Base { public Base() { Console.WriteLine($"{GetType().Name} Created"); } } public class Account : Base,IAccount { } public class Message : Base, IMessage { } public class Tool : Base, ITool { } public static void Run() { Console.WriteLine("Run Method Begin..."); //root provider var rootProvider = new ServiceCollection() .AddTransient<IAccount, Account>() .AddScoped<IMessage, Message>() .AddSingleton<ITool, Tool>() .BuildServiceProvider(); //create child provider var childProvider1 = rootProvider.CreateScope().ServiceProvider; var childProvider2 = rootProvider.CreateScope().ServiceProvider; GetService<IAccount>(childProvider1); GetService<IMessage>(childProvider1); GetService<ITool>(childProvider1); Console.WriteLine(); GetService<IAccount>(childProvider2); GetService<IMessage>(childProvider2); GetService<ITool>(childProvider2); Console.WriteLine("Run Method End..."); } public static void GetService<T>(IServiceProvider serviceProvider) { serviceProvider.GetService<T>(); serviceProvider.GetService<T>(); } }
调用Demo.Run() 输出结果
Run Method Begin...
Account Created
Account Created
Message Created
Tool Created
Account Created
Account Created
Message Created
Run Method End...
调用GetService<T>方法获取实例进行实例的创建,Account、Message、Tool都继承了Base类,因此在被创建时,会调用Base类的构造函数;
AddTransient => 每次请求都会创建一个新的实例
可以看到子容器childProvider1中 Account对象被创建了两次,因为可以看出AddTransient每次请求时都会创建一个新的实例;
AddScoped => 同一个请求中返回同一个实例
在子容器的作用域中进行查找,同一个子容器中只会创建一次;所以childProvider1中调用两次GetService()方法只创建一次实列;
childProvider2也只创建了一次Message
AddSingleton => 整个应用程序只会创建一次;单例永远从根容器rootProvider中查找
Tool 因为是Singleton 类型,因此整个程序中只创建了一次;
Part 2 : IDisposable
第二部分我们来看看创建的这些对象是何时进行释放的
在以上的代码中,将Base类实现IDisposable接口
public class Base : IDisposable { public Base() { Console.WriteLine($"{GetType().Name} Created"); } public void Dispose() { Console.WriteLine($"{GetType().Name} Disposed"); } }
在Run方法中使用Using来测试结果:
public static void Run() { //root provider using (ServiceProvider root = new ServiceCollection() .AddTransient<IAccount, Account>() .AddScoped<IMessage, Message>() .AddSingleton<ITool, Tool>() .BuildServiceProvider()) { using (var scope = root.CreateScope()) { var child = scope.ServiceProvider; child.GetService<IAccount>(); child.GetService<IMessage>(); child.GetService<ITool>(); Console.WriteLine("Child provider begin dispose"); } Console.WriteLine("Child provider disposed "); Console.WriteLine("Root provider begin dispose "); } Console.WriteLine("Root provider disposed "); }
测试结果
Account Created
Message Created
Tool Created
Child provider begin dispose
Message Disposed
Account Disposed
Child provider disposed
Root provider begin dispose
Tool Disposed
Root provider disposed
可以看出 AddTransient 和 AddScoped 在使用完child容器后,就调用了Base的 Dispose() ;而 AddSingle则在使用完root容器后再释放的;