我正在尝试建立一个我有基础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会抛出错误,因此解决另一个通用似乎已经出来了。我不知道该怎么办。有没有办法做这样的事情?有没有更好的方法来获得没有装饰器的预期功能?我们在考虑部分课程,但这有一系列问题。
任何帮助将不胜感激!
答案 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的答案解决了您的代码所带来的设计问题,因此他的解决方案可以带您到更好的地方。