C# “验证就是投掷”;无法强制转换类型为';BaseModel';输入';衍生车型&x27&引用;

C# “验证就是投掷”;无法强制转换类型为';BaseModel';输入';衍生车型&x27&引用;,c#,fluentvalidation,C#,Fluentvalidation,当我尝试编写验证器时,我发现FluentValidation(v8.2.0)存在一个奇怪的问题: System.InvalidCastException HResult=0x80004002 消息=无法将“BaseModel”类型的对象强制转换为“DerivedModel”类型。 来源=FluentValidation 堆栈跟踪: 在c:\Projects\FluentValidation\src\FluentValidation\Internal\ConditionBuilder1.c_uu显

当我尝试编写验证器时,我发现FluentValidation(v8.2.0)存在一个奇怪的问题:

System.InvalidCastException HResult=0x80004002 消息=无法将“BaseModel”类型的对象强制转换为“DerivedModel”类型。 来源=FluentValidation 堆栈跟踪: 在c:\Projects\FluentValidation\src\FluentValidation\Internal\ConditionBuilder
1.c_uu显示Class2\u 0.g_u条件| 0(ValidationContext上下文)中,在c:\Projects\FluentValidation\Internal\ConditionBuilder.cs:第62行
在C:\Projects\FluentValidation\src\FluentValidation\Internal\PropertyRule.cs中的FluentValidation.Internal.PropertyRule.d\uu 67.MoveNext()处:第270行
在System.Linq.Enumerable.SelectManySingleSelectorIterator中
2.MoveNext() 在System.Linq.Enumerable.WhereEnumerableInterator
1.MoveNext()中
在C:\Projects\FluentValidation\src\FluentValidation\AbstractValidator.cs中的FluentValidation.AbstractValidator
1.Validate(ValidationContext`1 context)中 在C:\Users\john\Documents\Visual Studio 2017\Projects\TestApp\TestApp\Program.cs中的TestApp.Program.d\uu 4.MoveNext()中:第76行 在System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()中 在System.Runtime.CompilerServices.TaskWaiter.HandleNonSuccessAndDebuggerNotification(任务任务)中 在TestApp.Program中。(字符串[]args)

我的模型和验证器: 如您所见,我正在使用
basemodelvalidater
验证
BaseModel
,而此引用没有任何地方引用
DerivedModel

有趣的是,如果我删除行
var-derivedmodelvalidater=new-derivedmodelvalidater(basemodelvalidater),它可以正常工作


是什么导致了这个异常以及如何解决它?

我实际上在我的web应用程序中偶尔看到这个问题-99%的时间它可以正常工作,但偶尔我会遇到这个问题。我向Jeremy Skinner,FluentValidation的作者,解释了发生了什么:

规则本质上与定义它们的验证器相关联。它们不是为了从一个验证器复制到另一个验证器而设计的。它们与定义它们的验证器以及定义它们所依据的类型有着内在的联系

每个条件块都有一个与之关联的唯一ID(该ID允许缓存条件的结果,因此它只执行一个,而不是针对其中的每个规则执行)。当您将规则从一个验证器复制到另一个验证器时,条件也会随之产生

简而言之:您不能在验证器之间共享单个规则对象

有问题的代码段是来自
DerivedModelValidator
的以下代码块:

foreach (var rule in baseValidator)
{
    AddRule(rule);
}
Jeremy为这个问题提供了两种不同的解决方案:

1.从包含共享规则的公共基本验证器类派生两个验证器类:
var baseModelValidator = new BaseModelValidator();
var derivedModelValidator = new DerivedModelValidator(baseModelValidator);

var baseModel = new BaseModel
{
    IsAlive = true,
    Name = "test2"
};
Console.WriteLine(baseModelValidator.Validate(baseModel).IsValid);
foreach (var rule in baseValidator)
{
    AddRule(rule);
}
public abstract class CommonModelValidator<T> : AbstractValidator<T> where T : BaseModel
{
    protected CommonModelValidator()
    {
        RuleFor(o => o.Name).Length(1, 20);
    }
}

public class BaseModelValidator : CommonModelValidator<BaseModel>
{
}

public class DerivedModelValidator : CommonModelValidator<DerivedModel>
{
    public DerivedModelValidator(BaseModelValidator baseValidator) 
        : base()
    {
        RuleFor(o => o.Age).GreaterThanOrEqualTo(0);
    }
}
public class BaseModelValidator : AbstractValidator<BaseModel>
{
    public BaseModelValidator()
    {
        RuleFor(o => o.Name).Length(1, 20);
    }
}

public class DerivedModelValidator : AbstractValidator<DerivedModel>
{
    public DerivedModelValidator(BaseModelValidator baseValidator)
    {
        RuleFor(o => o).SetValidator(baseValidator);
        RuleFor(o => o.Age).GreaterThanOrEqualTo(0);
    }
}