.net 框架中 有2種方法實現控制反轉
service locator — 在程式中主動向服務容器索取
dependency injection — 在物件生成時,服務容器在建構式注入到物件私有成員
服務留存期 ( Service Lifetime )
- Singleton : 整個 Process 只建立一個 Instance,任何時候都共用它。
- Scoped : 在網頁 Request 處理過程共用一個 Instance。(接到瀏覽器請求到回傳結果前的執行期間)
- Transient : 每次要求元件時就建立一個新的,永不共用。
參考 黑暗執行緒筆記 : https://blog.darkthread.net/blog/aspnet-core-di-notes/
Console App 中 實作 IOC
這次的範例是用 service locator 方法,在微軟的官方文檔中有明確寫道,不建議使用這種方法取得物件,建議使用 DI依賴注入,在註冊服務時也建議使用抽象介面,依賴於抽象達到依賴反轉。
範例:
Program.cs
- Install Nuget package & using
Microsoft.Extensions.DependencyInjection
2. new ServiceCollection()
3. 註冊到 service container
- AddSingleton
- AddScoped
- AddTransient
4. using ServiceProvider
using Microsoft.Extensions.DependencyInjection;
namespace Ioc;
class Program
{
static void Main(string[] args)
{
ServiceCollection service = new ServiceCollection();
// service.AddSingleton<TestService>();
// service.AddScoped<TestService>();
service.AddTransient<TestService>();
using (ServiceProvider serviceProvider = service.BuildServiceProvider())
{
TestService t1 = serviceProvider.GetService<TestService>();
TestService t2 = serviceProvider.GetService<TestService>();
t1.Name = "小明";
t2.Name = "小華";
t1.SayHi();
t2.SayHi();
Console.WriteLine("是否為相同物件: " + Object.ReferenceEquals(t1, t2));
}
}
}
TestService.cs
- Add interface
- Add class
namespace Ioc;
public interface ITestService
{
public string Name { get; set; }
public void SayHi();
}
public class TestService : ITestService
{
public string Name { get; set; } = "";
public void SayHi()
{
Console.WriteLine($"Hi, 我是{Name}");
}
}
執行結果
AddSingleton
AddScoped
AddTransient
與我想像中的相同,Singleton和Scoped會得到相同的物件,Transient會得到不同的物件。
參考 楊中科 微軟MVP .net 教程範例:https://www.youtube.com/watch?v=iEeyxFQeYYI&list=PL9sJKk6XPMxehYCui7OysUV6trlBbJ4T_&index=35&ab_channel=杨中科
小結:
Singleton 整個 Application 共用同一個實體適合無狀態的服務,Scoped 在一個 Request 中會注入一個新的實體,不會在不同 Request 中共用,可以作為有狀態的服務,Transient 會在每次注入中都是注入新的實體,就會佔用到比較多的記憶體。
另外 Scoped 有延伸可以客製化 scope 的方法,所以再一次請求中如果劃分不同的 scope 那也可以獲得到不同的實體。
參考: ATai IT邦幫忙 、微軟官方文檔