编辑
2025-09-27
C#
00

目录

Scrutor 简介
设置 WinForms 项目
添加必要的 NuGet 包
实现依赖注入
创建服务和接口
配置 Host 和 Services
使用服务
增加一个ILoggingService接口
新增FrmEdit 窗体
代码
修改Form1窗体
Form1 代码修改
修改Program
结论

在 .NET 开发中,依赖注入(DI)是一种常用的设计模式,它有助于减少代码之间的耦合,使得代码更加模块化和易于测试。虽然在 ASP.NET Core 中内置了强大的依赖注入支持,但在 Windows Forms(WinForms)应用程序中实现 DI 可能会比较复杂。本文将介绍如何在 WinForms 应用中使用 Scrutor 来简化服务注册过程,并提供一些实用的示例。

Scrutor 简介

Scrutor 是一个扩展库,它扩展了 .NET Core 的 IServiceCollection,提供了更多灵活的方式来注册服务,尤其是通过扫描程序集来自动注册服务非常实用。这在大型项目中尤其有用,可以避免手动注册每个服务。

设置 WinForms 项目

首先,确保你有一个 WinForms 项目。在 Visual Studio 中创建一个新的 WinForms .NET Core 项目。

添加必要的 NuGet 包

在项目中,我们需要添加以下 NuGet 包:

  • Microsoft.Extensions.DependencyInjection
  • Microsoft.Extensions.Hosting
  • Scrutor

你可以通过 NuGet 包管理器或使用包管理控制台来安装这些包:

Bash
Install-Package Microsoft.Extensions.DependencyInjection Install-Package Microsoft.Extensions.Hosting Install-Package Scrutor

image.png

实现依赖注入

创建服务和接口

首先,我们需要定义一些服务和接口。例如,我们创建一个 IMessageService 接口和一个实现该接口的 MessageService 类:

C#
public interface IMessageService { void SendMessage(string message); } public class MessageService : IMessageService { public void SendMessage(string message) { MessageBox.Show(message, "Message"); } }

配置 Host 和 Services

在 WinForms 应用中配置 DI 容器和 Host。我们可以在 Program.cs 中设置:

C#
internal static class Program { /// <summary> /// The main entry point for the application. /// </summary> [STAThread] static void Main() { // To customize application configuration such as set high DPI settings or default font, // see https://aka.ms/applicationconfiguration. ApplicationConfiguration.Initialize(); var host = CreateHostBuilder().Build(); using (var serviceScope = host.Services.CreateScope()) { var services = serviceScope.ServiceProvider; var mainForm = services.GetRequiredService<Form1>(); Application.Run(mainForm); } } static IHostBuilder CreateHostBuilder() => Host.CreateDefaultBuilder() .ConfigureServices((hostContext, services) => { services.Scan(scan => scan .FromAssemblyOf<Form1>() // 从 Form1 所在的程序集开始扫描 .AddClasses(classes => classes.AssignableTo<IMessageService>()) // 添加所有实现 IMessageService 接口的类 .AsImplementedInterfaces() // 将它们注册为实现的接口 .WithScopedLifetime()); // 使用作用域生命周期 services.AddScoped<Form1>(); // 将 Form1 注册为作用域服务 }); }

使用服务

MainForm.cs,我们可以通过构造函数注入使用 IMessageService

C#
public partial class MainForm : Form { private readonly IMessageService _messageService; public MainForm(IMessageService messageService) { InitializeComponent(); _messageService = messageService; } private void btnShowMessage_Click(object sender, EventArgs e) { _messageService.SendMessage("hello world!"); } }

image.png

增加一个ILoggingService接口

C#
public interface ILoggingService { void Log(string message); }

LoggingService服务

C#
public class LoggingService : ILoggingService { public void Log(string message) { // 实现日志记录逻辑,例如输出到控制台 File.AppendAllText("app.log", message); } }

新增FrmEdit 窗体

image.png

代码

C#
public partial class FrmEdit : Form { private readonly ILoggingService _loggingService; public FrmEdit(ILoggingService loggingService) { InitializeComponent(); _loggingService = loggingService; } private void btnWriteLog_Click(object sender, EventArgs e) { _loggingService.Log("FrmEdit..."); } }

修改Form1窗体

image.png

Form1 代码修改

C#
private readonly IMessageService _messageService; private readonly ILoggingService _loggingService; private readonly IServiceProvider _serviceProvider; public Form1(IMessageService messageService, ILoggingService loggingService, IServiceProvider serviceProvider) { InitializeComponent(); this._messageService = messageService; _loggingService = loggingService; _serviceProvider = serviceProvider; } private void btnShowEdit_Click(object sender, EventArgs e) { using (var scope = _serviceProvider.CreateScope()) { var frmEdit = scope.ServiceProvider.GetRequiredService<FrmEdit>(); frmEdit.ShowDialog(); } }

修改Program

C#
static IHostBuilder CreateHostBuilder() => Host.CreateDefaultBuilder() .ConfigureServices((hostContext, services) => { services.Scan(scan => scan .FromAssemblyOf<Form1>() // 从 Form1 所在的程序集开始扫描 .AddClasses(classes => classes.AssignableTo<IMessageService>()) // 添加所有实现 IMessageService 接口的类 .AddClasses(classes => classes.AssignableTo<ILoggingService>()) // 添加所有实现 ILoggingService 接口的类 .AsImplementedInterfaces() // 将它们注册为实现的接口 .WithScopedLifetime()); // 使用作用域生命周期 services.AddScoped<Form1>(); // 将 Form1 注册为作用域服务 services.AddScoped<FrmEdit>(); // 将 Form2 注册为作用域服务 services.AddScoped<IMessageService, MessageService>(); services.AddScoped<ILoggingService, LoggingService>(); });

结论

通过使用 Scrutor 和 Microsoft.Extensions.DependencyInjection,我们可以在 WinForms 应用中轻松实现依赖注入,这为我们提供了更高的灵活性和可测试性。上述示例展示了如何自动扫描和注册服务,以及如何在应用程序中使用它们。这种方法可以帮助我们构建更加解耦和维护更加简单的 WinForms 应用。

本文作者:技术老小子

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!