在WPF開發(fā)中,依賴注入(Dependency Injection)和控制反轉(zhuǎn)(Inversion of Control)是程序解耦的關(guān)鍵,在當(dāng)今軟件工程中占有舉足輕重的地位,兩者之間有著密不可分的聯(lián)系。今天就以一個(gè)簡單的小例子,簡述如何在WPF中實(shí)現(xiàn)依賴注入和控制反轉(zhuǎn),僅供學(xué)習(xí)分享使用,如有不足之處,還請(qǐng)指正。
?文章來源:http://www.zghlxwxcb.cn/news/detail-741814.html
什么是依賴注入和控制反轉(zhuǎn)?
?
依賴注入又稱為依賴項(xiàng)注入,那什么是依賴項(xiàng)呢?比如在一個(gè)類A中,實(shí)現(xiàn)某中功能,而此功能是另外一個(gè)類B實(shí)現(xiàn)的,那就說明A依賴B,B就是A的依賴項(xiàng)?;蛘呤橇硪粋€(gè)對(duì)象A所依賴的對(duì)象B。示例如下:
namespace DemoIoc
{
public class MessageWriter
{
public void Print(string message)
{
Console.WriteLine($"MessageWriter.Write(message: \"{message}\")");
}
}
public class Worker : BackgroundService
{
private readonly MessageWriter writer = new();
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
writer.Print($"Worker running at: {DateTimeOffset.Now}");
await Task.Delay(1_000, stoppingToken);
}
}
}
}
注意:在上述示例中,Worker類依賴于MessageWriter類,所以MessageWriter就是Worker的依賴項(xiàng)。 硬編碼的依賴項(xiàng)(如前面的示例)會(huì)產(chǎn)生問題,應(yīng)避免使用。
強(qiáng)依賴關(guān)系具有以下幾個(gè)問題:
- 如果要用不同的實(shí)現(xiàn)替換?
MessageWriter
,必須修改?Worker
?類。 - 如果?
MessageWriter
?具有依賴項(xiàng),則必須由?Worker
類對(duì)其進(jìn)行配置,且很難進(jìn)行初始化。 - 這種實(shí)現(xiàn)很難進(jìn)行單元測(cè)試。
那如何解決上述依賴關(guān)系所造成的弊端呢?答案就是依賴項(xiàng)注入??赏ㄟ^如下幾個(gè)步驟實(shí)現(xiàn):
- 使用接口或基類將依賴關(guān)系實(shí)現(xiàn)抽象化。
- 在服務(wù)容器中注冊(cè)依賴關(guān)系。
- 將服務(wù)注入到使用它的類的構(gòu)造函數(shù)中。
?.NET 提供了一個(gè)內(nèi)置的服務(wù)容器?IServiceProvider。 服務(wù)通常在應(yīng)用啟動(dòng)時(shí)注冊(cè),并追加到?IServiceCollection。 添加所有服務(wù)后,可以使用?BuildServiceProvider?創(chuàng)建服務(wù)容器。?框架負(fù)責(zé)創(chuàng)建依賴關(guān)系的實(shí)例,并在不再需要時(shí)將其釋放。
簡單一句話說:依賴注入(DI)將所依賴的對(duì)象參數(shù)化,接口化,并且將依賴對(duì)象的創(chuàng)建和釋放剝離出來,這樣就做到了解耦,并且實(shí)現(xiàn)了控制反轉(zhuǎn)(IoC)。
控制反轉(zhuǎn)(IoC)具有如下兩個(gè)特點(diǎn):
- 高等級(jí)的代碼不能依賴低等級(jí)的代碼;
- 抽象接口不能依賴具體實(shí)現(xiàn);
控制反轉(zhuǎn)解決代碼的強(qiáng)耦合,增加了代碼的可擴(kuò)展性。依賴注入將依賴具體實(shí)現(xiàn)類和控制實(shí)現(xiàn)類的創(chuàng)建和釋放,變成了依賴接口或抽象類,不再控制接口的創(chuàng)建和釋放。兩者之間相輔相成,互相成就。
?
WPF中實(shí)現(xiàn)依賴注入的步驟
?
1. 安裝DI庫
?
首先創(chuàng)建一個(gè)WPF應(yīng)用程序,然后在Nuget包管理器中安裝微軟提供的依賴注入庫【Microsoft.Extensions.DependencyInjection】,如下所示:
?
2. 創(chuàng)建接口和實(shí)現(xiàn)類
?
創(chuàng)建測(cè)試用的接口ITextService和實(shí)現(xiàn)類TextService,如下所示:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DemoIoc
{
public interface ITextService
{
public string GetText();
}
public class TextService : ITextService
{
public string GetText()
{
return DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
}
}
}
?
3. 接口注入
?
在需要調(diào)用的地方(如:MainWindow)進(jìn)行ITextService接口注入,如下所示:
namespace DemoIoc
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private ITextService textService;
public MainWindow(ITextService textService)
{
this.textService = textService;
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
this.txtCurrentTime.Text = textService.GetText();
}
}
}
注意:以上可以看出MainWindow依賴ITextService接口,而不依賴于接口的實(shí)現(xiàn)。這樣就實(shí)現(xiàn)了依賴注入。
?
4. 配置容器
?
在啟動(dòng)程序App.xaml.cs中,添加當(dāng)前對(duì)象成員,和服務(wù)提供對(duì)象,并在實(shí)例化服務(wù)對(duì)象的時(shí)候一次性注冊(cè),以便在后續(xù)需要的時(shí)候進(jìn)行獲取。如下所示:
namespace DemoIoc
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
/// <summary>
/// 獲取當(dāng)前 App 實(shí)例
/// </summary>
public new static App Current => (App)Application.Current;
/// <summary>
/// 獲取存放應(yīng)用服務(wù)的容器
/// </summary>
public IServiceProvider ServiceProvider { get; }
public App()
{
ServiceProvider = ConfigureServices();
}
/// <summary>
/// 配置應(yīng)用的服務(wù)
/// </summary>
private static IServiceProvider ConfigureServices()
{
var serviceCollection = new ServiceCollection()
.AddSingleton<ITextService,TextService>()
.AddSingleton<MainWindow>();
return serviceCollection.BuildServiceProvider();
}
protected override void OnStartup(StartupEventArgs e)
{
var mainWindow = ServiceProvider.GetRequiredService<MainWindow>();
mainWindow.Show();
}
}
}
注意:在此示例中,MainWindow通過服務(wù)注冊(cè)的方式進(jìn)行實(shí)例化,所以需要?jiǎng)h除默認(rèn)的App.xaml中StartUri屬性設(shè)置,否則將提示默認(rèn)構(gòu)造函數(shù)不存在。
?
示例測(cè)試
?
經(jīng)過上述步驟,就實(shí)現(xiàn)了WPF中依賴注入和控制反轉(zhuǎn),測(cè)試結(jié)果如下:
說明:正常輸出,則表示依賴注入成功。
?
參考文檔
?
1. .Net依賴項(xiàng)注入:https://learn.microsoft.com/zh-cn/dotnet/core/extensions/dependency-injection
?
以上就是依賴注入和控制反轉(zhuǎn)的全部內(nèi)容,希望可以拋磚引玉,一起學(xué)習(xí),共同進(jìn)步。文章來源地址http://www.zghlxwxcb.cn/news/detail-741814.html
到了這里,關(guān)于深入理解WPF中的依賴注入和控制反轉(zhuǎn)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!