使用Simple Injector解析通用装饰器

Car*_*son 4 c# generics dependency-injection decorator simple-injector

我正在尝试构建一个结构,其中我有一个基础IValidator <>接口,将基于一些元数据为我们的系统生成.我们希望给未来的开发人员灵活地1)重新生成IValidator <>如果需要的话的具体实现,而不会干扰任何手工编写的代码和2)添加装饰器来IValidator <>,以便能够扩展功能,而不会干扰自动生成的代码.

我希望有一些方法可以在运行时使用Simple Injector的RegisterDecorator方法来解析泛型装饰器,这样我们的开发团队就不需要每次添加装饰器时都更新组合根.

以下是一些示例类/接口

public interface IValidator<T> where T : class
{
    void Validate(T entity);
}
public class ClientValidator : IValidator<Client>
{
    public void Validate(Client entity)
    {
        //Auto-generated
    }
}
public class UserValidator : IValidator<User>
{
    public void Validate(User entity)
    {
        //Auto-generated
    }
}
public class ClientValidatorDecorator : IValidator<Client> 
{
    private readonly IValidator<Client> clientValidator;

    public ClientValidatorDecorator(IValidator<Client> clientValidator)
    {
        this.clientValidator = clientValidator;
    }
    public void Validate(Client entity)
    {
        //New rules
        this.clientValidator.Validate(entity);
    }
}
public class UserValidatorDecorator : IValidator<User>
{
    private readonly IValidator<User> userValidator;

    public UserValidatorDecorator(IValidator<User> userValidator)
    {
        this.userValidator = userValidator;
    }
    public void Validate(User entity)
    {
        //New rules
        this.userValidator.Validate(entity);
    }
}
public class ValidationContext
{
    private readonly IValidator<Client> client;
    private readonly IValidator<User> user;

    public ValidationContext(IValidator<Client> client, IValidator<User> user)
    {
        this.client = client;
        this.user = user;
    }
}
Run Code Online (Sandbox Code Playgroud)

我正在尝试这样做:

public void RegisterServices(Container container)
{
    container.Register(typeof(IValidator<>), AssemblyManifest.GetAssemblies());
    container.RegisterDecorator(typeof(IValidator<>), GetType, Lifestyle.Transient, UseType);
}
private static Type GetType(DecoratorPredicateContext ctx)
{
    //Return appropriate Decorator
}
private static bool UseType(DecoratorPredicateContext ctx)
{
    //Predicate
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,除非我解决一个具体的类型RegisterDecorator抛出一个错误,所以解决另一个通用似乎.我不知道该怎么办.有没有办法做这样的事情?有没有更好的方法来获得没有装饰器的预期功能?我们在考虑部分课程,但这有一系列问题.

任何帮助将不胜感激!

quj*_*jck 6

您可以使用复合验证器IValidator<>根据需要添加实现,而不是插入装饰器.此解决方案将允许代码包含IValidator<>相同类型的多个.

在内部,您的代码仍然可以依赖于一个IValidator<T>可以解析为CompositeValidator调用零或更多验证器的单个代码,具体取决于在运行时在容器中注册的内容.

复合验证器:

public class CompositeValidator<T> : IValidator<T>
{
    public readonly IEnumerable<IValidator<T>> validators;

    public CompositeValidator(IEnumerable<IValidator<T>> validators)
    {
        this.validators = validators;
    }

    public void Validate(T item)
    {
        foreach(var validator in this.validators)
        {
            validator.Validate(item);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

容器配置如下:

var assemblies = new[] { typeof(IValidator<>).Assembly };
var container = new Container();
container.RegisterCollection(typeof(IValidator<>), assemblies);
container.Register(typeof(IValidator<>), typeof(CompositeValidator<>));
Run Code Online (Sandbox Code Playgroud)

其中assemblies变量包含要搜索验证器的所有程序集.

当您解决IValidator<User>使用container.GetInstance<IValidator<User>>()或通过构造函数注入时,您将返回CompositeValidator<User>内部引用任何和所有内容 IValidator<User>的内容.