有没有办法有条件地将类型注册为 .NET 依赖注入的回退?

Is there a way to conditionally register types as fallback with .NET dependency injection?

我们目前使用 SimpleInjector 作为我们的 DI 容器,通过使用 ICommand and IQuery<TResult> and ICommandHandler<TCommand> and IQueryHandler<TQuery, TResult> 来实现命令查询分离 (CQS) 模式接口。

我们也使用装饰器模式来进行面向方面的编程。对于我们的装饰器之一,我们使用 FluentValidation 来执行特定命令或查询的验证逻辑。

使用 SimpleInjector,可以有条件地注册类型。当我们有一个 not 没有相应验证器的命令或查询时,这对我们的 FluentValidation 装饰器很有用。然后我们使用 NullValidator<T> 作为后备,什么也不做。 SimpleInjector documentation 中描述了这种情况,对于 FluentValidation 情况看起来像这样:

public class NullValidator<T> : AbstractValidator<T>
{
}
container.RegisterConditional(
    typeof(IValidator<>),
    typeof(NullValidator<>),
    c => !c.Handled); // Applied if no other validator matches

NullValidator<T> 是必需的,因为总是应用装饰器并且总是注入 IValidator<T>。对于不存在的特定验证器,使用 NullValidator<T>。这是命令的 FluentValidation 装饰器的构造函数:

public FluentValidationCommandHandlerDecorator(
    IValidator<TCommand> validator,
    ICommandHandler<TCommand> decoratee)
    {
        this.validator = validator ?? throw new ArgumentNullException(nameof(validator));
        this.decoratee = decoratee ?? throw new ArgumentNullException(nameof(decoratee));
    }

这工作得很好,但现在我们正在评估删除对 SimpleInjector 的依赖,并使用 .NET 依赖注入(IServiceCollection 来自 Microsoft.Extensions.DependencyInjection)结合 Scrutor 进行注册我们的 ICommandHandler<T>IQueryHandler<TQuery, TResult> 实现以及我们的装饰器。

是否有任何方法可以执行类似的条件注册逻辑或后备机制,如 .NET DI 框架中支持的 SimpleInjector?

我设法通过在 FluentValidationCommandHandlerDecorator 装饰器中注入一个 IEnumerable<IValidator<T>> 而不是一个 IValidator<T> 实例来解决这个问题。在那种情况下,我根本不需要 NullValidator<T>,如果没有可用于特定命令或查询的验证器,则会注入一个空集合。

必须更改 SimpleInjector 以注册 IValidator<T> 个实例的集合:

container.Collection.Register(typeof(IValidator<>), assemblies);

Microsoft.Extensions.DependencyInjection DI 容器支持注入 IEnumerable<IValidator<T>> 开箱即用,无需在注册中更改任何内容。