使用简单注入器解析通用装饰器
Resolving generic Decorators with Simple Injector
我正在尝试构建一个结构,其中我有一个基础 IValidator<> 接口,该接口将根据一些元数据为我们的系统生成。我们希望为未来的开发人员提供灵活性,以便 1) 如果需要,在不干扰任何手写代码的情况下重新生成 IValidator<> 的具体实现,以及 2) 向 IValidator<> 添加装饰器,以便能够在不干扰自动验证的情况下扩展功能生成的代码。
我希望有一些方法可以在运行时使用 Simple Injector 的 RegisterDecorator 方法解析通用装饰器,这样我们的开发团队就不需要在每次添加装饰器时都去更新组合根。
这里有一些例子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;
}
}
我们正在尝试做这样的事情:
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
}
不幸的是,除非我解析具体类型 RegisterDecorator 会抛出错误,否则解析另一个泛型似乎无法解决。我不确定如何进行。有没有办法做这样的事情?有没有更好的方法在没有装饰器的情况下获得预期的功能?我们考虑的是部分 类,但这有其自身的一系列问题。
任何帮助将不胜感激!
您可以使用 Composite Validator 来根据需要添加 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);
}
}
}
容器配置如下:
var assemblies = new[] { typeof(IValidator<>).Assembly };
var container = new Container();
container.RegisterCollection(typeof(IValidator<>), assemblies);
container.Register(typeof(IValidator<>), typeof(CompositeValidator<>));
其中 assemblies
变量包含您要搜索验证器的所有程序集。
当您使用 container.GetInstance<IValidator<User>>()
或通过构造函数注入解析 IValidator<User>
时,您会返回 CompositeValidator<User>
,它在内部引用任何和所有 IValidator<User>
。
使用批量注册获取装饰器类型的方法是调用接受 TypesToRegisterOptions
对象的 GetTypesToRegister
方法重载。这样你也可以指示 SI return 装饰器。
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 的回答解决了您的代码的设计问题,因此他的解决方案将您带到了一个更好的地方。
我正在尝试构建一个结构,其中我有一个基础 IValidator<> 接口,该接口将根据一些元数据为我们的系统生成。我们希望为未来的开发人员提供灵活性,以便 1) 如果需要,在不干扰任何手写代码的情况下重新生成 IValidator<> 的具体实现,以及 2) 向 IValidator<> 添加装饰器,以便能够在不干扰自动验证的情况下扩展功能生成的代码。
我希望有一些方法可以在运行时使用 Simple Injector 的 RegisterDecorator 方法解析通用装饰器,这样我们的开发团队就不需要在每次添加装饰器时都去更新组合根。
这里有一些例子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;
}
}
我们正在尝试做这样的事情:
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
}
不幸的是,除非我解析具体类型 RegisterDecorator 会抛出错误,否则解析另一个泛型似乎无法解决。我不确定如何进行。有没有办法做这样的事情?有没有更好的方法在没有装饰器的情况下获得预期的功能?我们考虑的是部分 类,但这有其自身的一系列问题。
任何帮助将不胜感激!
您可以使用 Composite Validator 来根据需要添加 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);
}
}
}
容器配置如下:
var assemblies = new[] { typeof(IValidator<>).Assembly };
var container = new Container();
container.RegisterCollection(typeof(IValidator<>), assemblies);
container.Register(typeof(IValidator<>), typeof(CompositeValidator<>));
其中 assemblies
变量包含您要搜索验证器的所有程序集。
当您使用 container.GetInstance<IValidator<User>>()
或通过构造函数注入解析 IValidator<User>
时,您会返回 CompositeValidator<User>
,它在内部引用任何和所有 IValidator<User>
。
使用批量注册获取装饰器类型的方法是调用接受 TypesToRegisterOptions
对象的 GetTypesToRegister
方法重载。这样你也可以指示 SI return 装饰器。
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 的回答解决了您的代码的设计问题,因此他的解决方案将您带到了一个更好的地方。