C#中的依赖注入Dependency Injection DI的实现步骤

 更新时间:2025年06月29日 09:32:31   作者:CoderIsArt  
在C#中依赖注入是一种实现控制反转的设计模式,用于解耦组件依赖关系,下面就来介绍一下依赖注入的实现步骤,具有一定的参考价值,感兴趣的可以了解一下

在C#中,依赖注入(Dependency Injection, DI)是一种实现控制反转(IoC)的设计模式,用于解耦组件依赖关系。以下是基于 .NET Core/ .NET 5+ 的依赖注入配置详细步骤和用法:

1. 基本概念

  • 服务(Service):被注入的依赖项(如接口、类)。
  • 容器(Container):管理服务的创建和生命周期(如 IServiceCollection)。
  • 生命周期
    • Transient:每次请求创建新实例。
    • Scoped:同一作用域内共享实例(如一次HTTP请求)。
    • Singleton:全局单例。

2. 配置依赖注入的步骤

步骤1:定义服务接口和实现类

// 定义接口
public interface IMyService
{
    string GetMessage();
}

// 实现接口
public class MyService : IMyService
{
    public string GetMessage() => "Hello from MyService!";
}

步骤2:注册服务到容器

在 Program.cs 或 Startup.cs(.NET 6+ 通常使用 Program.cs):

var builder = WebApplication.CreateBuilder(args);

// 注册服务(生命周期可选)
builder.Services.AddTransient<IMyService, MyService>();      // 瞬时
builder.Services.AddScoped<IMyService, MyService>();         // 作用域
builder.Services.AddSingleton<IMyService, MyService>();      // 单例

// 直接注册类(无接口)
builder.Services.AddTransient<MyService>();

步骤3:注入服务到目标类

通过构造函数注入:

public class MyController : ControllerBase
{
    private readonly IMyService _service;

    // 构造函数自动注入
    public MyController(IMyService service)
    {
        _service = service;
    }

    [HttpGet]
    public IActionResult Get()
    {
        return Ok(_service.GetMessage());
    }
}

3. 在非Web应用(如WPF/控制台)中使用DI

WPF 示例

安装NuGet包

Install-Package Microsoft.Extensions.DependencyInjection

配置DI容器(在 App.xaml.cs):

public partial class App : Application
{
    public IServiceProvider ServiceProvider { get; private set; }

    protected override void OnStartup(StartupEventArgs e)
    {
        var services = new ServiceCollection();
        
        // 注册服务
        services.AddTransient<IMyService, MyService>();
        services.AddSingleton<MainWindow>(); // 注册主窗口

        ServiceProvider = services.BuildServiceProvider();
        
        // 解析主窗口并显示
        var mainWindow = ServiceProvider.GetRequiredService<MainWindow>();
        mainWindow.Show();
    }
}

在窗口/ViewModel中注入

public partial class MainWindow : Window
{
    public MainWindow(IMyService service)
    {
        InitializeComponent();
        var message = service.GetMessage(); // 使用注入的服务
    }
}

4. 高级用法

4.1 注入多个实现(命名或策略模式)

// 注册多个实现
builder.Services.AddTransient<IMyService, ServiceA>();
builder.Services.AddTransient<IMyService, ServiceB>();

// 通过 IEnumerable<T> 获取所有实现
public class Consumer
{
    public Consumer(IEnumerable<IMyService> services)
    {
        foreach (var service in services)
        {
            service.DoSomething();
        }
    }
}

4.2 使用工厂模式动态创建服务

builder.Services.AddTransient<IMyService>(provider => 
{
    var config = provider.GetRequiredService<IConfiguration>();
    return new MyService(config.GetValue<string>("Mode"));
});

4.3 生命周期管理注意事项

  • 避免Singleton依赖Scoped服务:可能导致Captive Dependency问题。
  • IDisposable处理:容器会自动释放实现了 IDisposable 的服务。

5. 常见问题解决

错误:未注册服务

System.InvalidOperationException: No service for type 'IMyService' has been registered.

解决:检查服务是否在 IServiceCollection 中正确注册。

循环依赖
重构代码以避免构造函数循环引用,或用 Lazy<T> 延迟初始化。

6. 总结表格

操作代码示例说明
注册Transient服务services.AddTransient<IMyService, MyService>();每次请求新实例
注册Scoped服务services.AddScoped<IMyService, MyService>();同一作用域内共享实例
注册Singleton服务services.AddSingleton<IMyService, MyService>();全局单例
构造函数注入public MyClass(IMyService service)自动解析依赖
手动解析服务var service = provider.GetRequiredService<IMyService>();从容器获取实例

通过以上步骤,可以灵活地在C#项目中配置和使用依赖注入,提升代码的可测试性和可维护性。

到此这篇关于C#中的依赖注入Dependency Injection DI的实现步骤的文章就介绍到这了,更多相关C# 依赖注入内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C#类的多态性详解

    C#类的多态性详解

    这篇文章主要为大家详细介绍了C#类的多态性,主要有两种:一是编译时的多态性,二是运行时的多态性,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2015-10-10
  • C#如何更改Word的语言设置

    C#如何更改Word的语言设置

    这篇文章主要为大家详细介绍了C#如何更改Word的语言设置,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-05-05
  • C#使用Automation实现控制自动拨打接听电话

    C#使用Automation实现控制自动拨打接听电话

    这篇文章主要为大家详细介绍了C#如何使用Automation实现控制自动拨打接听电话,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2024-02-02
  • C#并行编程之数据并行Tasks.Parallel类

    C#并行编程之数据并行Tasks.Parallel类

    这篇文章介绍了C#并行编程之数据并行Tasks.Parallel类,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-05-05
  • c# 理解csredis库实现分布式锁的详细流程

    c# 理解csredis库实现分布式锁的详细流程

    这篇文章主要介绍了c# 理解csredis实现分布式锁,该库本身已经足够完善,这里我画蛇添足一下,为了方便自己的使用,本文通过实例代码给大家详细介绍,需要的朋友可以参考下
    2022-02-02
  • 关于C# 调用Dll 传递字符串指针参数的问题

    关于C# 调用Dll 传递字符串指针参数的问题

    这篇文章主要介绍了C# 调用Dll传递字符串指针参数,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-01-01
  • C#使用LOCK实现线程同步

    C#使用LOCK实现线程同步

    这篇文章介绍了C#使用LOCK实现线程同步的方法,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-04-04
  • 关于C#执行顺序带来的一些潜在问题

    关于C#执行顺序带来的一些潜在问题

    这篇文章主要给大家介绍了关于C#执行顺序带来的一些潜在问题,文中通过示例代码介绍的非常详细,对大家学习或者使用C#具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2020-08-08
  • C语言使用getch()读取方向键

    C语言使用getch()读取方向键

    getch()是编程中所用的函数,这个函数是一个不回显函数,当用户按下某个字符时,函数自动读取,无需按回车,有的C语言命令行程序会用到此函数做游戏,但是这个函数并非标准函数,要注意移植性
    2021-07-07
  • C# 重写Notification提示窗口的示例代码

    C# 重写Notification提示窗口的示例代码

    本文主要介绍了C# 重写Notification提示窗口的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-04-04

最新评论