首先我們在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容器后再釋放的;
