IOC在Web API 中是經常使用的,但是在一些WPF項目并不是經常使用或者被人熟知的,我把相關依賴注入的內容又做了一次學習和整理
什么是依賴注入?
依賴注入是一種設計模式和軟件設計原則,用于實現 控制反轉。它的核心思想是:將對象所依賴的其他對象的創建和管理職責從對象內部轉移到外部容器或框架,從而降低代碼的耦合度,提高可測試性、可維護性和靈活性。
依賴注入的主要優點
- 降低耦合度(Decoupling):
○ 組件(如 OrderService)只依賴于接口(如 IOrderRepository),而不依賴于具體實現(如 SqlOrderRepository)。具體實現的切換由外部容器控制。 - 提高可測試性(Testability):
○ 可以輕松地為依賴項創建 Mock 或 Stub 對象(實現相同的接口),并在測試時注入到被測試對象中。這使得單元測試獨立、快速且可靠(不依賴數據庫、網絡等外部資源)。 - 提高可維護性和可擴展性:
○ 更容易替換依賴的實現(只需在容器配置中更改綁定關系)。
○ 更容易添加新功能(添加新實現并注冊到容器即可)。
○ 代碼更清晰,職責更單一。 - 促進代碼重用:
○ 解耦后的組件更容易在不同的上下文中復用。 - 管理對象生命周期:
○ DI 容器通常提供對依賴對象生命周期的管理(如單例、每次請求創建新實例、線程內單例等),簡化了資源管理。
NET 項目使用依賴注入
● Microsoft.Extensions.DependencyInjection.Abstractions
● Microsoft.Extensions.Dependencyinjection
核心類型
● IServiceCollection 服務注冊
● ServiceDescriptor 服務注冊時的信息
● IServiceProvider 具體的容器
● IServiceScope 子容器生命周期
生命周期
1.AddSingleton 單例生命周期
● 在整個進程中,多次創建對象都是同一個對象—遵循了單例模式;
● 第一次創建以后,在內存中,保存下來了,下次創建–直接使用內存,而不是再去全新的創建
ServiceCollection serviceDescriptors = new ServiceCollection();
serviceDescriptors.AddSingleton<ITestService, TestService>();
ServiceProvider serviceProvider = serviceDescriptors.BuildServiceProvider();ITestService testService1 = serviceProvider.GetService<ITestService>();
ITestService testService2 = serviceProvider.GetService<ITestService>();bool isflg = object.ReferenceEquals(testService1, testService2);
Console.WriteLine($"testService1==testService2 {isflg}"); //true
2.AddScoped 作用域生命周期
● 每一個作用域(serviceProvider)內創建的某一個類的對象是同一個實例
● 不同的作用域(serviceProvider)內創建的同一個類的對象是不同的實例
● 這種?命周期適?于需要在特定作?域內共享對象實例的情 況,?如Web應?程序中的每個HTTP請求
ServiceCollection serviceDescriptors = new ServiceCollection();
serviceDescriptors.AddScoped<ITestService, TestService>();
ServiceProvider serviceProvider1 = serviceDescriptors.BuildServiceProvider();ITestService testService1 = serviceProvider1.GetService<ITestService>();
ITestService testService2 = serviceProvider1.GetService<ITestService>();
bool isflg = object.ReferenceEquals(testService1, testService2);
Console.WriteLine($"testService1==testService2 {isflg}");//trueServiceProvider serviceProvider2 = serviceDescriptors.BuildServiceProvider();
ITestService testService3 = serviceProvider2.GetService<ITestService>();
ITestService testService4 = serviceProvider2.GetService<ITestService>();
bool isflg1 = object.ReferenceEquals(microphone3, microphone4);
Console.WriteLine($"testService3==testService4 {isflg1}");//truebool isflg2 = object.ReferenceEquals(testService1, testService3);
Console.WriteLine($"microphone1==microphone3 {isflg2}");//false
3.AddTransient 瞬時生命周期
● 每一次都會創建出一個全新的實例
● 如果需要每次都創建實例—瞬時
ServiceCollection serviceDescriptors = new ServiceCollection();
serviceDescriptors.AddTransient<ITestService, Microphone>();
ServiceProvider serviceProvider = serviceDescriptors.BuildServiceProvider();
ITestService testService1 = serviceProvider.GetService<ITestService>();
ITestService testService2 = serviceProvider.GetService<ITestService>();
bool isflg = object.ReferenceEquals(testService1, testService2);
Console.WriteLine($"testService1==testService2 {isflg}"); //fals
依賴注入方式
1.構造函數注入
在執行構造函數的時候,能夠把構造函數依賴的參數自動構造出來,傳遞進來;–無限層級
public class MainViewModel
{private readonly ITestService _testService;public MainViewModel(ITestService testService){this._testService = testService;}
}
2.屬性注入
在某個類的內部包含的有屬性,在構造出整個類的時候,這個類中的某些屬性,能夠自動根據屬性的類型–自動構造出實例–賦值給屬性;
官方不支持需要引入第三方框架
public class MainViewModel
{[Inject]public ITestService TestService { get; set; }public MainViewModel(){}
}
3.方法注入
在某個類的內部,包含的有一些特殊的方法,在構造這個類的實例的時候,能夠自動的把方法執行掉,方法需要的參數—自動構建實例,傳遞進來;
? [FromServices] 需要引用 NuGet 包:Microsoft.AspNetCore.Mvc(僅限 ASP.NET Core 項目)。
public class MainViewModel
{public MainViewModel(){}public void Test([FromServices] ITestService testService){testService.GetMessage();}
}
原生WPF項目使用IOC
public partial class App : Application
{public static App CurrentApp { get; private set; } = null!;public App(){CurrentApp = this;}public IServiceProvider ServiceProvider { get; set; } = null!;protected override void OnStartup(StartupEventArgs e){base.OnStartup(e);var serviceCollection = new ServiceCollection();ConfigureServices(serviceCollection);this.ServiceProvider = serviceCollection.BuildServiceProvider();var mainWindow = this.ServiceProvider.GetService<MainWindow>();mainWindow?.Show();}private void ConfigureServices(IServiceCollection services){services.AddSingleton<MainWindow>();services.AddSingleton<MainViewModel>();services.AddTransient<ITestService, TestService>();}
}
public partial class MainWindow : Window{public MainWindow(){InitializeComponent();this.DataContext = App.CurrentApp.ServiceProvider.GetService(typeof(MainViewModel));}
}