使用Simple Injector解析通用装饰器

时间:2016-02-24 20:22:59

标签: c# generics dependency-injection decorator simple-injector

我正在尝试建立一个我有基础IValidator<>的结构。将基于某些元数据为我们的系统生成的接口。我们希望为未来的开发人员提供灵活性1)重新生成IValidator的具体实现<>如果需要不干扰任何手写代码和2)添加装饰器到IValidator<>能够在不干扰自动生成代码的情况下扩展功能。

我想在运行时使用Simple Injector的RegisterDecorator方法解决通用装饰器,这样我们的开发团队就不需要每次添加装饰器时都更新组合根。

以下是一些示例类/接口

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
}

我正在尝试这样做:

{{1}}

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

任何帮助将不胜感激!

2 个答案:

答案 0 :(得分:6)

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

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

复合验证器:

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

容器配置如下:

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

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

使用IValidator<User>或通过构造函数注入解析container.GetInstance<IValidator<User>>()后,您将返回CompositeValidator<User>,其内部引用任何IValidator<User>个。{/ p>

答案 1 :(得分:2)

使用批量注册获取类型装饰器的方法是调用接受GetTypesToRegister对象的TypesToRegisterOptions方法重载。这样你就可以指示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);
}

请注意我不建议使用此代码。 @ qujck的答案解决了您的代码所带来的设计问题,因此他的解决方案可以带您到更好的地方。