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

如何借助.NET Core DI装饰自定义工厂创建的对象?

带运行时参数的服务工厂如何结合容器驱动的装饰机制?

问题场景

假设我们有一个依赖仅能在运行时解析的参数的服务:

interface IFooService
{
    void DoServicyStuff();
}

class MyFooService : IFooService
{
    private readonly string _peskyValue;

    public MyFooService(string somePeskyRuntimeArgument)
    {
        _peskyValue = somePeskyRuntimeArgument;
    }

    public void DoServicyStuff()
    {
        // 使用_peskyValue执行业务逻辑
    }
}

由于参数只能在运行时提供,我们通常会用工厂模式将构造参数转为方法参数:

interface IFooServiceFactory
{
    IFooService CreateService(string runtimeParam);
}

class FooServiceFactory : IFooServiceFactory
{
    public IFooService CreateService(string runtimeParam)
    {
        return new MyFooService(runtimeParam);
    }
}

但这种模式下,为IFooService添加装饰器会遇到一系列问题:

  • 直接调用容器GetRequiredService<IFooService>会因找不到string类型的注册而失败;
  • 手动在工厂内创建装饰器耦合度极高,新增装饰器必须修改工厂代码;
  • 为每个服务装饰器编写对应的工厂装饰器会大幅增加代码复杂度。

现有手动方案的弊端

1. 工厂内手动创建装饰器

耦合度极高,新增装饰器必须修改工厂核心逻辑:

public IFooService CreateService(string runtimeParam)
{
    return new LoggingFooService(new MyFooService(runtimeParam));
}

2. 工厂装饰器模式

需为每个服务装饰器编写对应的工厂装饰器,实现繁琐且重复:

abstract class FooServiceFactoryDecorator : IFooServiceFactory
{
    protected readonly IFooServiceFactory _innerFactory;

    protected FooServiceFactoryDecorator(IFooServiceFactory innerFactory)
    {
        _innerFactory = innerFactory;
    }

    public virtual IFooService CreateService(string runtimeParam)
    {
        return _innerFactory.CreateService(runtimeParam);
    }
}

class LoggingFooServiceFactory : FooServiceFactoryDecorator
{
    public LoggingFooServiceFactory(IFooServiceFactory innerFactory) : base(innerFactory) { }

    public override IFooService CreateService(string runtimeParam)
    {
        return new LoggingFooService(_innerFactory.CreateService(runtimeParam));
    }
}

// 注册时需装饰工厂而非服务
services.AddTransient<IFooServiceFactory, FooServiceFactory>()
        .Decorate<IFooServiceFactory, LoggingFooServiceFactory>();

3. 泛化工厂装饰器

虽能复用逻辑,但维护难度大,添加装饰器的语法不够简洁:

class DecoratedFooServiceFactory<TDecorator> : FooServiceFactoryDecorator
    where TDecorator : IFooService
{
    private readonly IServiceProvider _serviceProvider;

    public DecoratedFooServiceFactory(IFooServiceFactory innerFactory, IServiceProvider serviceProvider) 
        : base(innerFactory)
    {
        _serviceProvider = serviceProvider;
    }

    public override IFooService CreateService(string runtimeParam)
    {
        return ActivatorUtilities.CreateInstance<TDecorator>(
            _serviceProvider, 
            _innerFactory.CreateService(runtimeParam));
    }
}

// 注册时需指定泛型参数
services.AddTransient<IFooServiceFactory, FooServiceFactory>()
        .Decorate<IFooServiceFactory, DecoratedFooServiceFactory<LoggingFooService>>();

以上方案均无法直接使用Scrutor的.Decorate<IFooService, TDecorator>简洁语法,且后续弃用工厂时需重新配置所有装饰器。

优雅实现方案

核心思路是让容器负责管理装饰器链,同时通过工厂委托传递运行时参数,无需手动编写装饰器相关的工厂类。

步骤1:注册服务与装饰器

首先注册底层服务MyFooService,然后为IFooService注册一个依赖运行时参数的创建逻辑,最后用Scrutor添加装饰器:

// 注册底层服务(自身类型)
services.AddTransient<MyFooService>();

// 注册接收运行时参数的IFooService创建委托
services.AddTransient<Func<string, IFooService>>(sp => runtimeParam =>
{
    // 创建底层服务实例
    var baseService = ActivatorUtilities.CreateInstance<MyFooService>(sp, runtimeParam);
    // 让容器为该实例应用所有已注册的装饰器
    return sp.GetRequiredService<IDecoratorFactory>().Decorate<IFooService>(baseService);
});

// 使用Scrutor添加装饰器(简洁语法)
services.Decorate<IFooService, LoggingFooService>();
services.Decorate<IFooService, ValidationFooService>(); // 新增装饰器只需一行代码

步骤2:简化工厂实现

现在工厂只需依赖Func<string, IFooService>委托,无需直接操作容器或手动创建装饰器:

class FooServiceFactory : IFooServiceFactory
{
    private readonly Func<string, IFooService> _fooServiceCreator;

    public FooServiceFactory(Func<string, IFooService> fooServiceCreator)
    {
        _fooServiceCreator = fooServiceCreator;
    }

    public IFooService CreateService(string runtimeParam)
    {
        return _fooServiceCreator(runtimeParam);
    }
}

// 注册工厂
services.AddTransient<IFooServiceFactory, FooServiceFactory>();

关键说明

  • 容器自动维护IFooService的装饰链,新增装饰器只需调用.Decorate<IFooService, TDecorator>(),无需修改工厂代码;
  • 装饰器自身的依赖(如ILogger<T>)会由容器自动注入,无需手动处理;
  • 后续若要弃用工厂,只需直接注入Func<string, IFooService>或调整注册逻辑,无需重新配置装饰器。

内容的提问来源于stack exchange,提问作者julealgon

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 05:03:28