Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/262.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用简单注入器解析泛型装饰器_C#_Generics_Dependency Injection_Decorator_Simple Injector - Fatal编程技术网

C# 使用简单注入器解析泛型装饰器

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时都去更新组合根 下

我正在尝试构建一个结构,在这个结构中,我有一个基本的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实际上是一个装饰器,以便在实际命令之前运行。因此,我只需要稍微改变一下,但这种风格最终确实适合我!谢谢你的回复!无论这是否是最好的解决方案,我都希望尽可能多地了解我正在使用的工具,因此这仍然是有价值的信息。这非常有效。然而,像上面一样,你怎么能强制执行某个命令?谢谢@丹尼洛伦