SetValidator()中的循环循环

时间:2013-09-15 18:53:08

标签: c# fluentvalidation

我有三个实体如下,它们相互链接如下:

class Class1 
{ 
   int id { get; set; }
   Class2 { get; set; } 
}

class Class2 
{
   int id { get; set; }
   Class3 { get; set; } 
}

class Class3 
{ 
   int id { get; set; }
   Class1 { get; set; } 
}

现在我为每个类创建了验证器,并为链接到它们的实体提供了SetValidator

//Class1 (and other classes) validator has following rules:
public class Class1Validator()
{
    public Class1Validator()
    {
        RuleFor(x => x.id).NotEqual(0).WithMessage("id is required.");
        RuleFor(x => x.Class2).SetValidator(new Class2Validator());
    }
}
public class Class2Validator()
{
    public Class2Validator()
    {
        RuleFor(x => x.id).NotEqual(0).WithMessage("id is required.");
        RuleFor(x => x.Class3).SetValidator(new Class3Validator());
    }
}
public class Class3Validator()
{
    public Class3Validator()
    {
        RuleFor(x => x.id).NotEqual(0).WithMessage("id is required.");
        RuleFor(x => x.Class1).SetValidator(new Class1Validator());
    }
}

//Now when following is called:
var validator = new Class1Validator();

当我检查Class1的验证时,它还包含Class2的验证程序,然后Class2包含Class3,最后也包含Class3Class1的验证器,它形成一个无限循环并抛出以下错误:

  

mscorlib.dll中出现未处理的“System.StackOverflowException”类型异常

并且在查看完整详细信息时显示:

  

无法计算表达式,因为当前线程处于堆栈溢出状态。

任何解决方案或我在这里做错了吗?


更新: 我也尝试过以下我可以限制验证器,如果object为null,但这不起作用:

When(x => x.Class1 != null, () => RuleFor(x => x.Class1).SetValidator(new Class1Validator()));

1 个答案:

答案 0 :(得分:0)

我找到了打破循环引用的方法:

  • SetValidator个调用移出构造函数,转换为Initialize()方法。
  • SetValidator()次调用中重用验证程序实例。例如,将验证程序实例存储为静态类中的静态字段。

好吧,我的言语不太好,所以这里是代码:

用于验证验证器实例并在其上调用Initialize()的类:

public static class Validators
{
    public static Class1Validator Class1Validator = new Class1Validator();
    public static Class2Validator Class2Validator = new Class2Validator();
    public static Class3Validator Class3Validator = new Class3Validator();

    static Validators()
    {
        Class1Validator.Initialize();
        Class2Validator.Initialize();
        Class3Validator.Initialize();
    }
}

验证器现在变为:

public class Class1Validator : AbstractValidator<Class1>
{
    public Class1Validator()
    {
        RuleFor(x => x.id).NotEqual(0).WithMessage("id is required.");
    }
    public void Initialize()
    {
        RuleFor(x => x.Class2).SetValidator(Validators.Class2Validator);            
    }
}
public class Class2Validator : AbstractValidator<Class2>
{
    public Class2Validator()
    {
        RuleFor(x => x.id).NotEqual(0).WithMessage("id is required.");
    }
    public void Initialize()
    {
        RuleFor(x => x.Class3).SetValidator(Validators.Class3Validator);            
    }
}
public class Class3Validator : AbstractValidator<Class3>
{
    public Class3Validator()
    {
        RuleFor(x => x.id).NotEqual(0).WithMessage("id is required.");
    }
    public void Initialize()
    {
        RuleFor(x => x.Class1).SetValidator(Validators.Class1Validator);            
    }
}

我测试了这个,似乎工作正常。例如:

var validator = Validators.Class1Validator;

var c1 = new Class1
    {
        id = 1,
        Class2 = new Class2
            {
                id = 2,
                Class3 = new Class3
                    {
                        id = 3,
                        Class1 = new Class1
                            {
                                id = 0,
                                Class2 = null
                            }
                    }
            }
    };

var result = validator.Validate(c1);
此处

result为false,因为内部Class1实例的Id0

我担心这种方法的线程安全性,但显然可以,如here所述:

  

验证器只能实例化一次 - 它们是线程安全的。