c#中实现依赖注入的核心是通过ioc容器将对象创建与依赖解析从业务逻辑中解耦,推荐使用构造函数注入;2. 实现步骤包括定义服务接口、实现接口、在消费者类中通过构造函数接收依赖、使用servicecollection注册服务并构建服务提供者;3. 依赖注入的优势在于解耦、提升可测试性、可维护性和可扩展性;4. 常见注入方式有构造函数注入(最推荐)、属性注入(适用于可选依赖)和方法注入(适用于特定场景);5. 在asp.net core中,di由内置容器支持,服务在program.cs中通过addtransient、addscoped、addsingleton注册,容器在运行时自动解析构造函数中的依赖,实现无缝注入。

C#中实现依赖注入,核心在于将对象的创建和依赖关系的解析从业务逻辑中解耦出来,通常会借助一个IoC(Inversion of Control)容器来管理这些对象的生命周期和依赖注入过程。最常见且推荐的做法是构造函数注入。
在C#中实现依赖注入,最直接且广泛采用的方式是结合接口和依赖注入容器。以下是一个基础的实现流程:
首先,你需要定义一个服务接口及其具体实现。这是DI的基础,因为我们总是面向接口编程。
// 1. 定义服务接口
public interface IMessageSender
{
void SendMessage(string message);
}
// 2. 实现服务接口
public class EmailSender : IMessageSender
{
public void SendMessage(string message)
{
Console.WriteLine($"Sending email: {message}");
// 实际中这里会有更复杂的邮件发送逻辑
}
}
// 3. 定义一个需要依赖的服务(消费者)
public class NotificationService
{
private readonly IMessageSender _messageSender;
// 构造函数注入:通过构造函数接收依赖
public NotificationService(IMessageSender messageSender)
{
_messageSender = messageSender ?? throw new ArgumentNullException(nameof(messageSender));
}
public void NotifyUser(string user, string message)
{
Console.WriteLine($"Notifying {user}...");
_messageSender.SendMessage(message);
}
}接下来,你需要一个依赖注入容器来注册这些服务,并在需要时解析它们。在现代C#应用,特别是ASP.NET Core中,通常会使用内置的DI容器。
using Microsoft.Extensions.DependencyInjection;
using System;
public class Program
{
public static void Main(string[] args)
{
// 4. 配置DI容器
var services = new ServiceCollection();
// 注册服务:将IMessageSender接口映射到EmailSender实现
// 这里使用AddTransient,表示每次请求都创建一个新的实例
services.AddTransient<IMessageSender, EmailSender>();
services.AddTransient<NotificationService>(); // NotificationService本身也可能被注入
// 构建服务提供者
var serviceProvider = services.BuildServiceProvider();
// 5. 从容器中获取实例(消费者)
// 容器会自动解析NotificationService所依赖的IMessageSender
var notificationService = serviceProvider.GetService<NotificationService>();
// 使用服务
notificationService.NotifyUser("Alice", "Your order has been shipped!");
// 尝试获取另一个实例,会发现EmailSender也是新的(因为是Transient)
var anotherNotificationService = serviceProvider.GetService<NotificationService>();
anotherNotificationService.NotifyUser("Bob", "Your account balance is low.");
}
}这个流程展示了DI的核心思想:应用程序代码(
NotificationService
IMessageSender
依赖注入这东西,初看可能觉得有点绕,不就是多写了个接口,又多加了个容器吗?但一旦你深入体验过,就会发现它带来的好处是实实在在的。对我个人而言,DI最大的魅力在于它彻底改变了我们对“耦合”的看法。以前写代码,一个类要用另一个类,直接
new
new
DI解决了这个问题,它让你的代码变得“松散耦合”。我们不再直接依赖具体的实现,而是依赖抽象(接口)。这样一来,当你需要替换一个功能模块时,比如从邮件发送换成短信发送,你只需要写一个新的实现类,然后在DI容器里改一下注册配置就行了,原有的业务逻辑代码几乎不用动。这种可插拔性,对于大型项目或者需要频繁迭代的场景来说,简直是救命稻草。
再者,就是测试性。没有DI的时候,一个类如果依赖了数据库、外部API等,单元测试时就很难隔离,往往需要启动整个环境。有了DI,我们可以轻松地为接口创建Mock或Stub实现,在测试时注入这些假对象,从而实现真正的单元测试,让测试变得更快、更可靠。维护性、可扩展性这些就更不用说了,都是水到渠成的好处。它就像给你的代码装上了一套灵活的骨架,让它能够适应未来的变化,而不是僵硬地被当前的需求所束缚。
在实践中,依赖注入主要有几种常见的实现模式,每种都有其适用场景,但也有各自的优缺点。理解它们能帮助你做出更明智的设计选择。
1. 构造函数注入 (Constructor Injection) 这是最推荐、最常用的方式。顾名思义,依赖项通过类的构造函数传入。
2. 属性注入 (Property Injection / Setter Injection) 通过公共属性(setter方法)来注入依赖。
3. 方法注入 (Method Injection) 依赖项作为方法的参数传入。
在我个人的开发实践中,我几乎总是优先选择构造函数注入。它强制你思考一个类的核心职责和它真正需要的依赖,如果构造函数变得臃肿,那往往是设计上需要调整的信号。属性注入我偶尔会用,但仅限于那些真正是“可选”的、或者是在特定框架(如某些ORM框架)中为了方便序列化或配置而不得不用的场景。方法注入则非常少用,通常只在一些非常具体、临时的功能中考虑。
ASP.NET Core在设计之初就把依赖注入作为其核心支柱之一,内置了一个非常强大且易于使用的DI容器。这意味着你在ASP.NET Core项目中,几乎不需要引入第三方DI库,就可以享受到DI带来的所有好处。
它的工作机制可以说相当优雅:
首先,所有的服务注册都集中在应用程序的启动阶段,具体来说,是在
Program.cs
Startup.cs
ConfigureServices
IServiceCollection
IMyService
MyServiceImplementation
// Program.cs var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddControllersWithViews(); // 比如注册MVC相关的服务 // 注册你的自定义服务 builder.Services.AddTransient<IMessageSender, EmailSender>(); // 每次请求都创建新实例 builder.Services.AddScoped<IUserRepository, UserRepository>(); // 每个HTTP请求创建一个实例 builder.Services.AddSingleton<ICacheService, MemoryCacheService>(); // 整个应用生命周期只创建一个实例 var app = builder.Build(); // ... 其他配置 app.Run();
这里面有几个关键的生命周期方法:
AddTransient<TService, TImplementation>()
AddScoped<TService, TImplementation>()
AddSingleton<TService, TImplementation>()
当ASP.NET Core应用程序运行时,DI容器会自动处理依赖的解析。比如,你的控制器(Controller)如果通过构造函数请求了
IMessageSender
EmailSender
new
public class HomeController : Controller
{
private readonly IMessageSender _messageSender;
private readonly IUserRepository _userRepository;
// ASP.NET Core的DI容器会自动解析并注入这些依赖
public HomeController(IMessageSender messageSender, IUserRepository userRepository)
{
_messageSender = messageSender;
_userRepository = userRepository;
}
public IActionResult Index()
{
_messageSender.SendMessage("Hello from Home Controller!");
var user = _userRepository.GetUserById(1);
ViewBag.UserName = user?.Name;
return View();
}
}这种内置的DI机制极大地简化了ASP.NET Core应用的开发,让代码结构更清晰,也更容易进行测试和维护。当然,理解不同生命周期的含义非常重要,选错了生命周期可能会导致一些意想不到的问题,比如
Scoped
Singleton
Singleton
Scoped
Scoped
以上就是C#的依赖注入(Dependency Injection)如何实现?的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号