c# – 如果我在属性中有验证属性,为什么Validator.TryValidateObject不验证类?

我创建了一个针对类的自定义ValidationAttribute.每当我尝试调用Validator.TryValidateObject时,这都会正确验证.但是当我在我的类中的属性中有其他ValidationAttribute时,验证结果不包含类级别验证的结果.

这是一个示例代码

[AttributeUsage(AttributeTargets.Class,AllowMultiple = false,Inherited = true)]
public class IsHelloWorldAttribute : ValidationAttribute
{
    public object _typeId = new object();
    public string FirstProperty { get; set; }
    public string SecondProperty { get; set; }

    public IsHelloWorldAttribute(string firstProperty,string secondProperty)
    {
        this.FirstProperty = firstProperty;
        this.SecondProperty = secondProperty; 
    }

    public override bool IsValid(object value)
    {
        PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(value);
        string str1 = properties.Find(FirstProperty,true).GetValue(value) as string;
        string str2 = properties.Find(SecondProperty,true).GetValue(value) as string;

        if (string.Format("{0}{1}",str1,str2) == "HelloWorld")
            return true;
        return false;
    }

    public override object TypeId
    {
        get
        {
            return _typeId;
        }
    }
}

这是我需要验证的类的代码

[IsHelloWorld("Name","Code",ErrorMessage="Is not Hello World")]
public class Myviewmodel : Baseviewmodel
{
    string name;
    string code;

    [required]
    public string Name
    {
        get { return model.Name; }
        set
        {
            if (model.Name != value)
            {
                model.Name = value;
                base.RaisePropertyChanged(() => this.Name);
            }
        }
    }        

    public string Code
    {
        get { return code; }
        set
        {
            if (code != value)
            {
                code = value;
                base.RaisePropertyChanged(() => this.Code);
            }
        }
    }
}

以下是我调用TryValidateObject方法方法

var validationContext = new ValidationContext(this,null,null);               
            var validationResults = new List<ValidationResult>();               
            Validator.TryValidateObject(this,validationContext,validationResults,true);

现在,如果我在Name属性中有[required]属性并且我尝试调用Validator.TryValidateObject,则验证结果只有一个,这是required验证的结果.但是当我从Name中删除[required]属性并离开IsHellowWorld属性然后调用TryValidateObject时,它会给我一个结果,那就是HellowWorldValidation的结果.

我需要做的是在类级别和属性级别上获得所有验证.我可以在不实现自己的TryValidateObject方法的情况下实现这一目标吗?

解决方法

这是因为如果检测到属性错误,则检查被短路.这是有道理的,因为类级别验证可能更昂贵,可能涉及回调,其他数据源调用等.

如果检测到属性错误,那么原来的逻辑就会停止.

在System.ComponentModel.DataAnnotations.Validator中:

public static bool TryValidateObject(object instance,ValidationContext validationContext,ICollection<ValidationResult> validationResults,bool validateallProperties)
    {
      if (instance == null)
        throw new ArgumentNullException("instance");
      if (validationContext != null && instance != validationContext.ObjectInstance)
        throw new ArgumentException(DataAnnotationsResources.Validator_InstanceMustMatchValidationContextInstance,"instance");
      bool flag = true;
      bool breakOnFirstError = validationResults == null;
      foreach (Validator.ValidationError validationError in Validator.GetobjectValidationErrors(instance,validateallProperties,breakOnFirstError))
      {
        flag = false;
        if (validationResults != null)
          validationResults.Add(validationError.ValidationResult);
      }
      return flag;
    }

请注意对Validator.GetobjectValidationErrors的调用,而Validator.GetobjectValidationErrors又被定义为:

private static IEnumerable<Validator.ValidationError> GetobjectValidationErrors(object instance,bool validateallProperties,bool breakOnFirstError)
        {
          if (instance == null)
            throw new ArgumentNullException("instance");
          if (validationContext == null)
            throw new ArgumentNullException("validationContext");
          List<Validator.ValidationError> list = new List<Validator.ValidationError>();

//Check for property errors here
          list.AddRange(Validator.GetobjectPropertyValidationErrors(instance,breakOnFirstError));

// Short circuits here if any found
          if (Enumerable.Any<Validator.ValidationError>((IEnumerable<Validator.ValidationError>) list))
            return (IEnumerable<Validator.ValidationError>) list;

// Class level validation occurs below this point
          IEnumerable<ValidationAttribute> validationAttributes = Validator._store.GetTypeValidationAttributes(validationContext);
          list.AddRange(Validator.GetValidationErrors(instance,validationAttributes,breakOnFirstError));
          if (Enumerable.Any<Validator.ValidationError>((IEnumerable<Validator.ValidationError>) list))
            return (IEnumerable<Validator.ValidationError>) list;
          IValidatableObject validatableObject = instance as IValidatableObject;
          if (validatableObject != null)
          {
            foreach (ValidationResult validationResult in Enumerable.Where<ValidationResult>(validatableObject.Validate(validationContext),(Func<ValidationResult,bool>) (r => r != ValidationResult.Success)))
              list.Add(new Validator.ValidationError((ValidationAttribute) null,instance,validationResult));
          }
          return (IEnumerable<Validator.ValidationError>) list;
        }

相关文章

在要实现单例模式的类当中添加如下代码:实例化的时候:frmC...
1、如果制作圆角窗体,窗体先继承DOTNETBAR的:public parti...
根据网上资料,自己很粗略的实现了一个winform搜索提示,但是...
近期在做DSOFramer这个控件,打算自己弄一个自定义控件来封装...
今天玩了一把WMI,查询了一下电脑的硬件信息,感觉很多代码都...
最近在研究WinWordControl这个控件,因为上级要求在系统里,...