注册有条件的开放泛型

Registering open generics with condition

是否可以在不指定实现类型的情况下使用 RegisterConditional(类似于 Register 的工作方式,但有条件)?

我正在使用 Simple Injector 为我的 CQRS/MVC 应用程序连接流畅的验证。到目前为止,注册验证器(由 MVC 和 CQRS 堆栈装饰器管道使用)一直很简单:

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

container.RegisterConditional(
    typeof(IValidator<>), 
    typeof(ValidateNothingDecorator<>), 
    Lifestyle.Singleton, 
    c => !c.Handled)

一项新要求意味着我需要实施类似于验证器的功能,但会提供警告。由于各种原因,我不想使用 Fluent Validation 的内置 "error level",这意味着我需要为给定类型创建额外的验证器,这当然会为单个类型验证错误提供多个注册。

我想做的是注册任何实现 IValidator<> 的东西,除非它也实现 IProvideWarnings,但我不想列出每个 class 来注册

public class MyCommand : IDefineCommand {...}
public class ValidateMyCommand : IValidator<MyCommand> {...}
public class ProvideWarningsForMyCommand : IValidator<MyCommand>, IProvideWarnings {...}
...
// would like something like... (this obviously does not work)
container.RegisterConditional(
    typeof(IValidator<>), 
    assemblies, 
    lifestyle, 
    c => !c.ImplementationType.GetInterfaces().Contains(typeof(IProvideWarnings)));

我的备用位置是找到所有实现 IValidator<> 但不实现 IProvideWarnings 的类型并将其传递给 Register,但是,我宁愿在注册中使用谓词来完成调用而不是不同的查找。

谢谢

我解决这个问题的方法是使用我的备用位置。

记住下面的代码中有一个非标准的方法(但应该足够直接),它看起来像:

 var validatorTypes = assemblies.SelectMany(a => a.GetTypes().Where(t =>
            t.IsClass && !t.IsAbstract && t.IsPublic &&
            t.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IValidator<>)) &&
            !t.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IProvideWarnings<>))
        )).ToList();

IocContainer.Register(typeof(IValidator<>), validatorTypes, IocContainer.DefaultLifestyle);

IocContainer.RegisterConditional(typeof(IValidator<>), typeof(ValidateNothingDecorator<>), Lifestyle.Singleton, c => !c.Handled && !c.ServiceType.DoesImplement(typeof(IProvideWarnings)));

正如您已经注意到的,Simple Injector 包含 Register 的重载,允许提供要注册的类型列表。虽然您可以自己反思程序集,但 Simple Injector 包含一个方便的 GetTypesToRegister 方法来为您完成这项工作。 GetTypesToRegister 会自动为您过滤掉装饰器和泛型类型定义。

以下注册就可以了:

var validatorTypes =
    container.GetTypesToRegister(typeof(IValidator<>))
        .Where(typeof(IProvideWarnings).IsAssignableFrom);

container.Register(typeof(IValidator<>), validatorTypes, lifestyle);