我还记得那个意识到我们的.NET代码库就像一颗定时炸弹的时刻。
凌晨3点,我正在调试电商结算系统中一个“简单”的变更。本应20分钟完成的任务,却变成了一场通宵马拉松,原因如下:
第二天早晨,我向首席架构师——一位从.NET Framework 2.0时代就开始构建企业系统的资深老兵——大吐苦水。
他微微一笑,说道:
“你在和代码搏斗,是因为没让控制反转容器发挥作用。”
接下来,他给我上了一堂依赖注入的实战大师课——这个习惯最终将我们的意大利面条代码变成了可维护、可测试且高性能的系统。
以下是我们的具体改造方法(附性能提升证明)。
多数.NET开发者以为自己用了依赖注入,因为他们会写这样的代码:
// "伪DI"反模式
public class OrderService
{
private readonly ILogger _logger = new Logger();
private readonly IPaymentGateway _gateway = ServiceLocator.Resolve<IPaymentGateway>();
}
问题在于:
架构师的黄金法则:
“如果类需要某个依赖,就必须通过构造函数索要。没有例外。”
在他的严格要求下,我们实现了:
// "正确DI"示范
public class OrderService
{
private readonly ILogger _logger;
private readonly IPaymentGateway _gateway;
public OrderService(ILogger logger, IPaymentGateway gateway)
{
_logger = logger;
_gateway = gateway;
}
}
为何有效?
改造前(混乱状态)
场景:为结算系统添加风控检测
// 隐藏的静态依赖
public void ProcessOrder(Order order)
{
var fraudChecker = new FraudDetectionService();
if (fraudChecker.IsHighRisk(order))
{
Logger.Instance.LogWarning("欺诈行为!");
// ...
}
}
问题:
改造后(清晰架构)
// 显式依赖
public class OrderProcessor
{
private readonly IFraudDetectionService _fraudService;
private readonly ILogger _logger;
public OrderProcessor(IFraudDetectionService fraudService, ILogger logger)
{
_fraudService = fraudService;
_logger = logger;
}
public void ProcessOrder(Order order)
{
if (_fraudService.IsHighRisk(order))
{
_logger.LogWarning("欺诈行为!");
}
}
}
重构后的生产环境性能提升:
(数据来自电商API基准测试)
替代遍地开花的日志代码:
// 为任何IOrderProcessor添加日志
public class LoggingOrderProcessorDecorator : IOrderProcessor
{
private readonly IOrderProcessor _inner;
private readonly ILogger _logger;
public LoggingOrderProcessorDecorator(IOrderProcessor inner, ILogger logger)
{
_inner = inner;
_logger = logger;
}
public void ProcessOrder(Order order)
{
_logger.LogInformation("订单处理中...");
_inner.ProcessOrder(order);
_logger.LogInformation("订单处理完成");
}
}
注册方式:
services.AddTransient<IOrderProcessor, CoreOrderProcessor>();
services.Decorate<IOrderProcessor, LoggingOrderProcessorDecorator>();
旧方式(脆弱):
var timeout = ConfigurationManager.AppSettings["PaymentTimeout"];
DI方式(类型安全):
// 1. 定义配置类
public class PaymentOptions
{
public int TimeoutSeconds { get; set; }
}
// 2. 注册
services.Configure<PaymentOptions>(Configuration.GetSection("Payment"));
// 3. 注入使用
public PaymentService(IOptions<PaymentOptions> options)
{
_timeout = options.Value.TimeoutSeconds;
}
// 接口定义
public interface IPaymentGatewayFactory
{
IPaymentGateway GetGateway(string countryCode);
}
// 实现
public class PaymentGatewayFactory : IPaymentGatewayFactory
{
private readonly IServiceProvider _provider;
public PaymentGatewayFactory(IServiceProvider provider)
{
_provider = provider;
}
public IPaymentGateway GetGateway(string countryCode)
{
return countryCode switch
{
"US" => _provider.GetRequiredService<StripeGateway>(),
"EU" => _provider.GetRequiredService<AdyenGateway>(),
_ => throw new NotSupportedException()
};
}
}
(基于.NET 8的1万次请求基准测试)
问题: 缺失的依赖直到运行时才报错
解决方案: 启动时验证
// 在Program.cs中
var sp = services.BuildServiceProvider();
sp.ValidateScopes(); // 当Scoped服务依赖Singleton时抛出异常
sp.ValidateOnBuild(); // 任何依赖缺失时立即抛出
采用严格DI六个月后:
new
或静态调用的类一旦全面采用DI,你会惊讶曾经没有它的日子是怎么过来的。