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(); // 堆代码 duidaima.com 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的依赖项。硬编码的依赖项(如前面的示例)会产生问题,应避免使用。
这种实现很难进行单元测试。
3.将服务注入到使用它的类的构造函数中。
.NET 提供了一个内置的服务容器 IServiceProvider。服务通常在应用启动时注册,并追加到 IServiceCollection。添加所有服务后,可以使用 BuildServiceProvider 创建服务容器。 框架负责创建依赖关系的实例,并在不再需要时将其释放。
简单一句话说:依赖注入(DI)将所依赖的对象参数化,接口化,并且将依赖对象的创建和释放剥离出来,这样就做到了解耦,并且实现了控制反转(IoC)。控制反转(IoC)具有如下两个特点:
1.高等级的代码不能依赖低等级的代码;2.抽象接口不能依赖具体实现;
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. 接口注入
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接口,而不依赖于接口的实现。这样就实现了依赖注入。
namespace DemoIoc { /// <summary> /// Interaction logic for App.xaml /// </summary> public partial class App : Application { /// <summary> /// 获取当前 App 实例 /// </summary> public new static App Current => (App)Application.Current; /// <summary> /// 获取存放应用服务的容器 /// </summary> public IServiceProvider ServiceProvider { get; } public App() { ServiceProvider = ConfigureServices(); } /// <summary> /// 配置应用的服务 /// </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通过服务注册的方式进行实例化,所以需要删除默认的App.xaml中StartUri属性设置,否则将提示默认构造函数不存在。