简体   繁体   English

使用Simple Injector解析通用装饰器

[英]Resolving generic Decorators with Simple Injector

I am trying to build out a structure where I have a base IValidator<> interface that will be generated for our system based on some metadata. 我正在尝试构建一个结构,其中我有一个基础IValidator <>接口,将基于一些元数据为我们的系统生成。 We want to give future developers the flexibility to 1) Regenerate the concrete implementations of IValidator<> if need be without disturbing any hand-written code and 2) Add decorators to IValidator<> to be able to extend the functionality without disturbing the auto-generated code. 我们希望为未来的开发人员提供灵活性:1)如果需要,可以重新生成IValidator <>的具体实现,而不会干扰任何手写代码; 2)将装饰器添加到IValidator <>,以便能够扩展功能而不会干扰自动化生成的代码。

I would like to have some way to resolve the generic decorators at runtime using the RegisterDecorator method of Simple Injector so our dev team does not need to go and update the composition root every time we add a decorator. 我希望有一些方法可以在运行时使用Simple Injector的RegisterDecorator方法来解析泛型装饰器,这样我们的开发团队就不需要每次添加装饰器时都更新组合根。

Here are some example classes/interfaces 以下是一些示例类/接口

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;
    }
}

We I am trying to do something like so: 我正在尝试这样做:

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
}

Unfortunately, unless I resolve a concrete type RegisterDecorator throws an error, so resolving another generic seems out. 不幸的是,除非我解决一个具体的类型RegisterDecorator抛出一个错误,所以解决另一个通用似乎。 I am not sure how to proceed. 我不知道该怎么办。 Is there a way to do something like this? 有没有办法做这样的事情? Is there a better way to get the intended functionality without decorators? 有没有更好的方法来获得没有装饰器的预期功能? We were thinking partial classes, but that has its own set of issues. 我们在考虑部分课程,但这有一系列问题。

Any help will be appreciated! 任何帮助将不胜感激!

Rather than plugging in decorators you could use a Composite Validator to enable the addition of IValidator<> implementations as required. 您可以使用Composite Validator来根据需要添加IValidator<>实现,而不是插入装饰器。 This solution would allow the code to contain multiple IValidator<> 's for the same type. 此解决方案允许代码包含多个相同类型的IValidator<>

Internally your code will still be able to depend on a single IValidator<T> which would resolve to the CompositeValidator that would call zero or more validators depending on what has been registered in the container at runtime. 在内部,您的代码仍然可以依赖于单个IValidator<T> ,它将解析为将调用零个或多个验证器的CompositeValidator ,具体取决于在运行时在容器中注册的内容。

The composite validator: 复合验证器:

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);
        }
    }
}

The container is configured like this: 容器配置如下:

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

where the assemblies variable contains all the assemblies you want to search for validators. 其中assemblies变量包含要搜索验证器的所有程序集。

When you resolve IValidator<User> using container.GetInstance<IValidator<User>>() or through constructor injection you get back CompositeValidator<User> which internally references any and all IValidator<User> 's. 当您使用container.GetInstance<IValidator<User>>()或通过构造函数注入解析IValidator<User>您将返回CompositeValidator<User> ,它在内部引用任何和所有IValidator<User>

The way to get decorators of a type using batch registration is by calling the GetTypesToRegister method overload that accepts a TypesToRegisterOptions object. 得到使用批量注册的类型的装饰的方法是通过调用GetTypesToRegister接受一个方法重载TypesToRegisterOptions对象。 This way you can instruct SI to return decorators as well. 这样你就可以指示SI返回装饰器。

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

var t1 = container.GetTypesToRegister(typeof(IValidator<>), assemblies);
var t2 = container.GetTypesToRegister(typeof(IValidator<>), assemblies,
    new TypesToRegisterOptions { IncludeDecorators = true });

foreach (Type t in t2.Except(t1)) {
    container.RegisterDecorator(typeof(IValidator<>), t);
}

Do note that I do not suggest using this code. 请注意,我不建议使用此代码。 @qujck's answer addresses the design issue you have with your code, and his solutions therefore brings you to a much better place. @ qujck的答案解决了您的代码所带来的设计问题,因此他的解决方案将带您到更好的地方。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM