如何在使用Activator的订单评估器工厂中实现依赖注入?
我现在有一个静态的OrderEvaluatorFactory,用来创建各类Order Evaluator。现在新增了一种Order Evaluator,它必须通过依赖注入获取IOrderProcessor(只能通过DI获取)。
当前工厂类通过特性查找要实例化的目标类型,再用System.Activator.CreateInstance()创建实例,代码如下:
public static class OrderEvaluatorFactory { private static Dictionary<Type, Type> orderEvaluatorTypesByOrderTypes = null; public static IOrderEvaluator CreateFor(OrderType ot) { if (orderEvaluatorTypesByOrderTypes == null) { orderEvaluatorTypesByOrderTypes = Utilities.TypeFinder<OrderTypeEvaluatorForAttribute, Type>.GetTypesByAttribute( typeof(OrderEvaluatorFactory).Assembly, type => typeof(IOrderEvaluator).IsAssignableFrom(type), attribute => attribute.For); } Type orderEvaluatorType = evaluatorTypesByOrderTypes[ot.GetType()]; if (evaluatorType == null) throw new Exception("No evaluator type found for " + ot.GetType()); return (IOrderEvaluator)Activator.CreateInstance(evaluatorType); } }
需要依赖注入的评估器代码:
[OrderTypeEvaluatorFor(typeof(SuperFastDeliveryOrder))] public class SuperFastDeliveryOrderEvaluator : IOrderEvaluator { private readonly IOrderProcessor orderProcessor; public SuperFastDeliveryOrderEvaluator(IOrderProcessor orderProcessor) { this.orderProcessor = orderProcessor; } public bool Eval(Customer cstm) { // 省略实现... return true; } }
这是目前唯一需要IOrderProcessor的评估器,所以我不想给所有其他评估器都传递这个对象(比如作为参数)。
现在遇到的问题:带IOrderProcessor的构造函数无法被Activator.CreateInstance()调用(它只会调用无参构造),而且我不想通过重载给所有对象都传IOrderProcessor。
我知道静态工厂模式和DI不太兼容,但找不到合适的解决方案。我考虑过把工厂改成非静态并加入DI容器,这样就能传入IOrderProcessor,但还是得保留Activator的逻辑。
请问怎么替换Activator,用更适配DI的方式,同时不用硬编码所有已知评估器的实例逻辑?
方案1:将工厂改为非静态,注入DI容器并使用容器解析实例
把静态工厂改成实例类,注入DI容器的服务提供器,让容器负责解析评估器的构造函数依赖,替代Activator.CreateInstance。
步骤如下:
- 改造工厂类为非静态,注入
IServiceProvider:
public class OrderEvaluatorFactory { private readonly IServiceProvider _serviceProvider; private Dictionary<Type, Type> _orderEvaluatorTypesByOrderTypes; public OrderEvaluatorFactory(IServiceProvider serviceProvider) { _serviceProvider = serviceProvider; InitializeTypeMapping(); } private void InitializeTypeMapping() { _orderEvaluatorTypesByOrderTypes = Utilities.TypeFinder<OrderTypeEvaluatorForAttribute, Type>.GetTypesByAttribute( typeof(OrderEvaluatorFactory).Assembly, type => typeof(IOrderEvaluator).IsAssignableFrom(type), attribute => attribute.For); } public IOrderEvaluator CreateFor(OrderType ot) { if (!_orderEvaluatorTypesByOrderTypes.TryGetValue(ot.GetType(), out var evaluatorType)) { throw new InvalidOperationException($"No evaluator type found for {ot.GetType()}"); } // 用DI容器解析实例,自动处理构造函数依赖 return (IOrderEvaluator)_serviceProvider.GetService(evaluatorType); } }
- 在DI容器中注册所有
IOrderEvaluator实现类及工厂:
// 以Microsoft.Extensions.DependencyInjection为例 services.AddTransient<IOrderProcessor, OrderProcessor>(); services.AddTransient<SuperFastDeliveryOrderEvaluator>(); // 注册其他无依赖的评估器 services.AddTransient<NormalOrderEvaluator>(); // 注册工厂本身 services.AddSingleton<OrderEvaluatorFactory>();
- 在需要创建评估器的地方,通过DI注入
OrderEvaluatorFactory并调用CreateFor方法即可。
方案2:针对性处理需要DI的评估器,其余保留Activator创建
如果不想全量用容器解析,可以在工厂里判断评估器类型是否需要IOrderProcessor,单独处理:
public class OrderEvaluatorFactory { private readonly IOrderProcessor _orderProcessor; private Dictionary<Type, Type> _orderEvaluatorTypesByOrderTypes; public OrderEvaluatorFactory(IOrderProcessor orderProcessor) { _orderProcessor = orderProcessor; InitializeTypeMapping(); } private void InitializeTypeMapping() { _orderEvaluatorTypesByOrderTypes = Utilities.TypeFinder<OrderTypeEvaluatorForAttribute, Type>.GetTypesByAttribute( typeof(OrderEvaluatorFactory).Assembly, type => typeof(IOrderEvaluator).IsAssignableFrom(type), attribute => attribute.For); } public IOrderEvaluator CreateFor(OrderType ot) { if (!_orderEvaluatorTypesByOrderTypes.TryGetValue(ot.GetType(), out var evaluatorType)) { throw new InvalidOperationException($"No evaluator type found for {ot.GetType()}"); } // 判断是否是需要IOrderProcessor的评估器 if (evaluatorType == typeof(SuperFastDeliveryOrderEvaluator)) { return new SuperFastDeliveryOrderEvaluator(_orderProcessor); } else { // 其他无依赖的用Activator创建 return (IOrderEvaluator)Activator.CreateInstance(evaluatorType); } } }
这种方式适合只有极少数评估器需要DI依赖的场景,但后续新增需要DI的评估器时,需手动添加判断逻辑,扩展性不如方案1。
方案3:容器批量注册+工厂解析
如果使用支持批量注册的DI容器(如Autofac),可以批量注册所有带OrderTypeEvaluatorForAttribute的评估器,再通过容器解析实例:
// Autofac注册示例 builder.RegisterAssemblyTypes(typeof(OrderEvaluatorFactory).Assembly) .Where(t => t.GetCustomAttribute<OrderTypeEvaluatorForAttribute>() != null) .As<IOrderEvaluator>() .InstancePerDependency(); builder.RegisterType<OrderEvaluatorFactory>().SingleInstance();
工厂类逻辑可参考方案1,用IServiceProvider或Autofac的IComponentContext解析实例。
内容的提问来源于stack exchange,提问作者Patric

