WPF 依赖注入

一、依赖注入的核心思想

依赖注入(Dependency Injection,DI)是一种设计模式,它的核心思想是“控制反转”(IoC),即将对象的创建和管理从应用程序代码中分离出来,交给外部容器来处理。主要概念包括:

  • 依赖:一个对象需要另一个对象来完成其工作,那么前者就依赖于后者。例如,一个orderService类可能依赖于一个ProductRepository类来获取产品信息;
  • 注入:将依赖的对象传递给需要它的对象,而不是让需要它的对象自己去创建依赖的对象。注入可以通过构造函数、属性或方法参数来实现;
  • 容器:一个管理对象创建和依赖关系的框架或库。容器负责实例化对象,解析依赖关系,并将依赖的对象注入到需要它们的对象中;

在传统的编程方式中,一个对象如果需要使用另一个对象,通常会在自身内部通过new关键字等方式直接创建被依赖的对象,这就导致了对象之间的紧密耦合。

而在IOC模式下,由IOC容器负责创建对象,并在对象需要时将其依赖的对象注入进去。这样,对象只需要关注自身的业务逻辑,而不需要关心依赖对象的创建过程,从而实现了对象之间依赖关系的解耦。

二、依赖注入的类型

1. 构造函数注入:依赖的对象通过类的构造函数传递。

public class MainViewModel
{
    private readonly IDataService _dataService;    
    public MainViewModel(IDataService dataService)
    {
        _dataService = dataService;
    }    
    //使用_dataService的方法
}

2. 属性注入:依赖的对象通过类的公共属性传递。

public class MainViewModel
{
    public IDataService DataService{get; set;}
}

3. 方法注入:依赖的对象通过类的方法参数传递。

public class MainViewModel
{
    public void SettingsService(IDataService DataService)
    {
        //使用DataService的方法
    }
}

三、WPF中实现依赖注入的常用方式

1. 使用Microsoft.Extensions.DependencyInjection

这是.NET Core/5+中官方推荐的DI容器(.NET Core/5+”涵盖 .NET Core 1.0-3.1 和 .NET 5/6/7/8),.NET提供了一个内置的服务容器IServiceProvider。服务通常在应用启动时注册,并追加到IServiceCollection。添加所有服务后,可以使用BuildServiceProvider创建服务容器。框架负责创建依赖关系的实例,并在不再需要时将其释放。

步骤:

  ① 首先创建一个WPF应用成,然后再Nuget包管理器中安装微软提供的依赖注入库[Microsoft.Extensions.DependencyInjection];

  ② 创建测试用的接口ITextService和实现类TextService:

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");
        }
    }
}

  ③ 在需要调用的地方(如:MainWindow)进行ITextService接口注入:可以看出MainWindow依赖ITextService接口,而不依赖于接口的实现。这样就实现了依赖注入。

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();
    }
}

  ④ 配置容器:在启动程序App.xaml.cs中,添加当前对象乘以,和服务提供对象,并在实例化服务对象的时候一次性注册,以便在后续需要的时候进行获取。

// 在App.xaml.cs 中配置服务
public partial class App : Application
{
    public IServiceProvider ServiceProvider{ get; private set;} //获取存放应用服务的容器
    
    protected override void OnStartup(StartupEventArgs e)
    {
     //配置应用的服务 
var serviceCollection = new ServiceCollection(); ConfigureServices(serviceCollection); ServiceProvider = serviceCollection.BuildServiceProvider();
//从依赖注入容器中获取一个`MainWindow`类型的实例。
var mainWindow = ServiceProvider.GetRequiredService<MainWindow>(); mainWindow.Show(); } private void ConfigureServices(IServiceCollection services) { services.AddSingleton<ITextService, TextService>(); Services.AddSingleton<MainWindow>(); } }
  • AddTransient瞬时模式:每次请求,都获取一个新的实例。使同一个请求获取多次也会是不同的实例
  • 使用方式:services.AddTransient<IOperation Transient, Operation>();
  • AddScoped:每次请求,都获取一个新的实例。同一个请求获取多次会得到相同的实例
  • 使用方式:services.AddScoped<IMyDependency, MyDependenсу>();
  • AddSingleton单例模式:每次都获取同一个实例
  • 使用方式:services.AddSingleton<IOperationSingleton, Operation>();

2. 使用依赖注入容器(如Autofac,Unity,Ninject等)

依赖注入容器是管理和创建对象及其依赖项的框架。它们可以大大简化依赖注入的实现,尤其是在大型应用中:

  • Autofac: 功能强大,性能好,支持模块化

  • Unity: 微软早期的DI容器,现在较少使用

  • Ninject: 语法简洁,适合快速开发

  • DryIoc: 高性能容器

  • Simple Injector: 强调编译时验证

--- Autofac:是 .NET 生态系统中非常流行的轻量级依赖注入(DI)框架,它以高性能和灵活性著称

// 创建注册器
var builder = new ContainerBuilder();

// 注册组件
builder.RegisterType<MyService>().As<IMyService>();

// 构建容器
var container = builder.Build();

// 从容器中解析组件
var myService = container.Resolve<IMyService>();

// 使用对象
myService.DoSomething();

--- Ninject:是一个轻量级、快速的依赖注入框架,以其"超级流畅"的接口和易用性著称。

// 创建内核(容器)
IKernel kernel = new StandardKernel();

// 基本绑定
kernel.Bind<IService>().To<ServiceImpl>();

// 解析服务
var service = kernel.Get<IService>();

// 构造函数注入示例
public class Consumer
{
    private readonly IService _service;
    
    public Consumer(IService service) // 自动注入
    {
        _service = service;
    }
}

--- DryIoc: 是另一个高性能的 .NET 依赖注入容器,以其出色的执行速度和简洁的 API 设计受到开发者青睐。

// 创建容器
var container = new Container();

// 注册服务
container.Register<IMessageService, EmailService>();

// 解析服务
var messageService = container.Resolve<IMessageService>();

// 使用服务
messageService.SendMessage("Hello, DryIoc!");

--- Unity:  是微软模式与实践团队开发的依赖注入容器,曾是微软官方推荐的DI解决方案。

// 创建容器
IUnityContainer container = new UnityContainer();

// 注册类型映射
container.RegisterType<IService, ServiceImpl>();

// 解析实例
IService service = container.Resolve<IService>();

// 构造函数注入示例
public class Consumer
{
    private readonly IService _service;
    
    public Consumer(IService service) // 自动注入
    {
        _service = service;
    }
}
 以Autofac进行举例:

① 基本项目结构:

MyWpfApp/
├── Views/
│   └── MainWindow.xaml
├── ViewModels/
│   └── MainViewModel.cs
├── Services/
│   ├── IDataService.cs
│   └── DataService.cs
└── App.xaml.cs

安装Autofac包:通过 NuGet 安装必要的包

Install-Package Autofac
Install-Package Autofac.Extensions.DependencyInjection

创建服务接口和实现

public interface IDataService
{
    string GetData();
}

public class DataService : IDataService
{
    public string GetData()
    {
        return "数据来自Autofac注入的服务";
    }
}

创建ViewModel

public class MainViewModel
{
    private readonly IDataService _dataService;
    
    public string DisplayData { get; set; }
    
    public MainViewModel(IDataService dataService)
    {
        _dataService = dataService;
        DisplayData = _dataService.GetData();
    }
}

配置Autofac容器

public partial class App : Application
{
    public static IContainer Container { get; private set; }
    
    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);        
        // 创建容器构建器
        var builder = new ContainerBuilder();        
        // 注册服务
        builder.RegisterType<DataService>().As<IDataService>();        
        // 注册ViewModels
        builder.RegisterType<MainViewModel>();        
        // 注册Views
        builder.RegisterType<MainWindow>();        
        // 构建容器
        Container = builder.Build();
        
        // 设置服务定位器(可选)
        var serviceProvider = new AutofacServiceProvider(Container);
        
        // 创建并显示主窗口
        var mainWindow = Container.Resolve<MainWindow>();
        mainWindow.Show();
    }
}

修改MainWindow以支持依赖注入

public partial class MainWindow : Window
{
    public MainWindow(MainViewModel viewModel)
    {
        InitializeComponent();
        DataContext = viewModel;
    }
}
<Window x:Class="MyWpfApp.Views.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Autofac Demo" Height="350" Width="525">
    <Grid>
        <TextBlock Text="{Binding DisplayData}" 
                   HorizontalAlignment="Center"
                   VerticalAlignment="Center"
                   FontSize="20"/>
    </Grid>
</Window>
Autofac高级用法示例

① 生命周期管理 

// 单例模式
builder.RegisterType<SingletonService>().As<ISingletonService>().SingleInstance();

// 每个依赖实例
builder.RegisterType<TransientService>().As<ITransientService>().InstancePerDependency();

// 每个生命周期作用域
builder.RegisterType<ScopedService>().As<IScopedService>().InstancePerLifetimeScope();

②  属性注入

public class SomeViewModel
{
    [Inject]  // 需要安装 Autofac.Extras.Attributed 包
    public ILogger Logger { get; set; }
}

// 注册时启用属性注入
builder.RegisterType<SomeViewModel>().PropertiesAutowired();

③ 模块化注册

public class ServicesModule : Module
{
    protected override void Load(ContainerBuilder builder)
    {
        builder.RegisterType<DataService>().As<IDataService>();
        builder.RegisterType<Logger>().As<ILogger>();
    }
}

// 在App.xaml.cs中使用模块
builder.RegisterModule<ServicesModule>();

④ 条件注册

// 仅在Debug模式下注册调试服务
#if DEBUG
builder.RegisterType<DebugLogger>().As<ILogger>();
#else
builder.RegisterType<ProductionLogger>().As<ILogger>();
#endif

 

posted @ 2025-08-16 18:37  LXLR  阅读(93)  评论(0)    收藏  举报