C# 使用简单注入器解析泛型装饰器
我正在尝试构建一个结构,在这个结构中,我有一个基本的IValidator接口,它将根据一些元数据为我们的系统生成。我们希望未来的开发人员能够灵活地1)在不干扰任何手写代码的情况下重新生成IValidator的具体实现,2)向IValidator添加装饰器,以便能够在不干扰自动生成的代码的情况下扩展功能 我希望能够在运行时使用Simple Injector的RegisterDecorator方法解决泛型decorator问题,这样我们的开发团队就不必在每次添加decorator时都去更新组合根 下面是一些示例类/接口C# 使用简单注入器解析泛型装饰器,c#,generics,dependency-injection,decorator,simple-injector,C#,Generics,Dependency Injection,Decorator,Simple Injector,我正在尝试构建一个结构,在这个结构中,我有一个基本的IValidator接口,它将根据一些元数据为我们的系统生成。我们希望未来的开发人员能够灵活地1)在不干扰任何手写代码的情况下重新生成IValidator的具体实现,2)向IValidator添加装饰器,以便能够在不干扰自动生成的代码的情况下扩展功能 我希望能够在运行时使用Simple Injector的RegisterDecorator方法解决泛型decorator问题,这样我们的开发团队就不必在每次添加decorator时都去更新组合根 下
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;
}
}
公共接口IValidator,其中T:class
{
无效验证(T实体);
}
公共类ClientValidator:IValidator
{
公共无效验证(客户实体)
{
//自动生成
}
}
公共类UserValidator:IValidator
{
公共无效验证(用户实体)
{
//自动生成
}
}
公共类ClientValidator装饰器:IValidator
{
专用只读IValidator客户端验证程序;
公共clientValidator装饰器(IValidator clientValidator)
{
this.clientValidator=clientValidator;
}
公共无效验证(客户实体)
{
//新规则
this.clientValidator.Validate(实体);
}
}
公共类UserValidatorDecorator:IValidator
{
专用只读IValidator用户验证程序;
公共userValidator装饰器(IValidator userValidator)
{
this.userValidator=userValidator;
}
公共无效验证(用户实体)
{
//新规则
this.userValidator.Validate(实体);
}
}
公共类ValidationContext
{
专用只读IValidator客户端;
专用只读IValidator用户;
公共验证上下文(IValidator客户端、IValidator用户)
{
this.client=client;
this.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
}
公共无效注册表服务(容器)
{
Register(typeof(IValidator),assemblymistent.GetAssemblies());
container.RegisterDecorator(typeof(IValidator)、GetType、lifety.Transient、UseType);
}
私有静态类型GetType(DecororPredicateContext ctx)
{
//返回合适的装饰器
}
私有静态bool UseType(decororPredicateContext ctx)
{
//谓词
}
不幸的是,除非我解析一个具体的类型RegisterDecorator,否则会抛出一个错误,所以解析另一个泛型似乎是错误的。我不知道如何进行。有没有办法做到这一点?有没有更好的方法在没有装饰的情况下获得预期的功能?我们考虑的是部分课程,但这有其自身的问题
任何帮助都将不胜感激 您可以使用复合验证器来根据需要添加
IValidator
实现,而不是插入decorator。此解决方案允许代码包含同一类型的多个ivalidor
在内部,您的代码仍然能够依赖单个IValidator
,它将解析为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);
}
}
}
public类CompositeValidator:IValidator
{
公共只读IEnumerable验证器;
公共复合验证器(IEnumerable验证器)
{
this.validators=验证程序;
}
公共无效验证(T项)
{
foreach(此.validators中的var验证器)
{
验证人。验证(项目);
}
}
}
容器的配置如下所示:
var assemblies = new[] { typeof(IValidator<>).Assembly };
var container = new Container();
container.RegisterCollection(typeof(IValidator<>), assemblies);
container.Register(typeof(IValidator<>), typeof(CompositeValidator<>));
var assemblies=new[]{typeof(IValidator).Assembly};
var container=新容器();
容器。注册收集(类型(IValidator),组件);
容器寄存器(typeof(IValidator)、typeof(CompositeValidator));
其中,assemblies
变量包含要搜索验证器的所有程序集
使用
container.GetInstance()解析IValidator
时
或通过构造函数注入,您可以返回内部引用任何和所有IValidator
的CompositeValidator
。使用批注册获取类型装饰器的方法是调用getTypeStoreRegister
方法重载,该重载接受TypeStoreRegisterOptions
对象。通过这种方式,您可以指示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);
}
container.Register(typeof(IValidator),assemblies);
var t1=container.getTypeStoreRegister(typeof(ivaliator),程序集);
var t2=容器.getTypeStoreRegister(typeof(ivaliditor)),程序集,
新的TypeStoreRegisterOptions{IncludeDecorators=true});
foreach(t2中的t型。除(t1)外){
容器.注册检测器(类型(IValidator),t);
}
请注意,我不建议使用此代码@qujck的答案解决了代码的设计问题,因此他的解决方案将您带到一个更好的地方。这是一个伟大的解决方案!我将由团队来运行它!谢谢你如何通过这种方式确保订单?这种方式唯一的缺点是它不再会连锁呼叫。如果所有验证都相等,则可以,但如果您有一个CommandHandlerValidator包装ICommandHandler,则此样式将不起作用。我希望此CompositeValidator实际上是一个装饰器,以便在实际命令之前运行。因此,我只需要稍微改变一下,但这种风格最终确实适合我!谢谢你的回复!无论这是否是最好的解决方案,我都希望尽可能多地了解我正在使用的工具,因此这仍然是有价值的信息。这非常有效。然而,像上面一样,你怎么能强制执行某个命令?谢谢@丹尼洛伦