You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何结合工厂模式与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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 16:42:38