如何结合工厂模式与Microsoft.Extensions.DependencyInjection实现带运行时参数的服务实例创建
使用Microsoft.Extensions.DependencyInjection结合工厂模式实现运行时传参创建服务实例
核心思路
每个ITransport实现类需要专属运行时配置,同时可能依赖DI容器管理的其他服务,因此要通过工厂封装DI的实例创建能力,兼顾运行时参数传入和已有依赖注入。
方案一:对应独立配置类的实现
适配你第一种结构(Car依赖CarConfig、Boat依赖BoatConfig)
1. 注册基础服务
在DI容器中注册所有ITransport实现类及其他依赖:
var services = new ServiceCollection(); // 按实际生命周期需求注册Transport实现类,示例用瞬态 services.AddTransient<Car>(); services.AddTransient<Boat>(); // 若有其他依赖(如ILogger),正常注册即可 // services.AddLogging();
2. 实现ITransportFactory
借助ActivatorUtilities.CreateInstance,自动从DI容器获取构造函数的其他依赖,再传入运行时配置:
public class TransportFactory : ITransportFactory { private readonly IServiceProvider _serviceProvider; public TransportFactory(IServiceProvider serviceProvider) { _serviceProvider = serviceProvider; } public ITransport GetTransport(string type, object config) { return type switch { nameof(Car) => ActivatorUtilities.CreateInstance<Car>(_serviceProvider, config), nameof(Boat) => ActivatorUtilities.CreateInstance<Boat>(_serviceProvider, config), _ => throw new ArgumentOutOfRangeException(nameof(type), "不支持的Transport类型") }; } }
3. 注册工厂并使用
// 注册工厂 services.AddTransient<ITransportFactory, TransportFactory>(); // 构建服务容器 var serviceProvider = services.BuildServiceProvider(); // 调用工厂创建实例 var factory = serviceProvider.GetRequiredService<ITransportFactory>(); var car = factory.GetTransport(nameof(Car), new CarConfig()); car.Move(); var boat = factory.GetTransport(nameof(Boat), new BoatConfig()); boat.Move();
方案二:统一配置接口的实现
适配你第二种结构(所有ITransport依赖IConfig接口)
1. 定义统一配置与Transport类
public interface IConfig { } public class CarConfig : IConfig { } public class BoatConfig : IConfig { } public class Car(IConfig config) : ITransport { public string Type => nameof(Car); public void Move() { /* 业务逻辑 */ } } public class Boat(IConfig config) : ITransport { public string Type => nameof(Boat); public void Move() { /* 业务逻辑 */ } }
2. 工厂实现
通过类型映射动态创建实例,兼容统一配置接口:
public class TransportFactory : ITransportFactory { private readonly IServiceProvider _serviceProvider; public TransportFactory(IServiceProvider serviceProvider) { _serviceProvider = serviceProvider; } public ITransport GetTransport(string type, IConfig config) { var transportType = type switch { nameof(Car) => typeof(Car), nameof(Boat) => typeof(Boat), _ => throw new ArgumentOutOfRangeException(nameof(type), "不支持的Transport类型") }; return (ITransport)ActivatorUtilities.CreateInstance(_serviceProvider, transportType, config); } }
3. 注册与使用
流程和方案一一致,注册后直接传入对应配置即可:
var services = new ServiceCollection(); services.AddTransient<Car>(); services.AddTransient<Boat>(); services.AddTransient<ITransportFactory, TransportFactory>(); var serviceProvider = services.BuildServiceProvider(); var factory = serviceProvider.GetRequiredService<ITransportFactory>(); var car = factory.GetTransport(nameof(Car), new CarConfig()); var boat = factory.GetTransport(nameof(Boat), new BoatConfig());
关键注意事项
- 生命周期控制:
ActivatorUtilities.CreateInstance创建的实例,其依赖的生命周期由DI容器管理,但实例本身需自行处理(如需容器管理可结合IServiceScope)。 - 类型安全优化:建议用枚举替代字符串类型参数,避免拼写错误,比如定义
public enum TransportType { Car, Boat }。 - 扩展性:新增Transport类型时,仅需在工厂的分支判断中添加对应类型,并在DI容器中注册新实现类即可。
内容的提问来源于stack exchange,提问作者Taras
相关产品推荐
相关产品推荐

