代码之家  ›  专栏  ›  技术社区  ›  Kirschstein

正在写入CompareTo DataAnnotation属性

  •  9
  • Kirschstein  · 技术社区  · 16 年前

    我有一种情况需要与字段进行比较(例如,确保开始时间早于结束时间)。我用的是 System.ComponentModel.DataAnnotations 用于验证的属性。

    我的第一个想法是这样的:

    public enum CompareToOperation
    {
        EqualTo,
        LessThan,
        GreaterThan
    }
    
    public class CompareToAttribute : ValidationAttribute
    {
        CompareToOperation _Operation;
        IComparable _Comparision;
    
        public CompareToAttribute(CompareToOperation operation, Func<IComparable> comparison)
        {
           _Operation = operation;
           _Comparision = comparison();
        }
    
        public override bool IsValid(object value)
        {
        if (!(value is IComparable))
            return false;
    
        switch (_Operation)
        {
            case CompareToOperation.EqualTo: return _Comparision.Equals(value);
            case CompareToOperation.GreaterThan: return _Comparision.CompareTo(value) == 1;
            case CompareToOperation.LessThan: return _Comparision.CompareTo(value) == -1;
        }
    
        return false;
        }
    }
    
    public class SimpleClass
    {
       public DateTime Start {get;set;}
       [CompareTo(CompareToOperation.GreaterThan, () => this.Start)] // error here
       public DateTime End {get;set;}
    }
    

    但是,这不起作用,存在一个编译器错误,该属性被标记为:

    Expression cannot contain anonymous methods or lambda expressions
    

    有人能解决这个问题吗?或者是验证一个字段与另一个字段的值的不同方法?

    4 回复  |  直到 15 年前
        1
  •  8
  •   James Manning    16 年前

    非常 不怎么灵活的丑陋方式是把它放在课堂上,并使用反射。我还没有测试过这个,所以我不确定它是否有效,但它确实可以编译:)

    public enum CompareToOperation
    {
        EqualTo,
        LessThan,
        GreaterThan
    }
    
    public class CompareToAttribute : ValidationAttribute
    {
        CompareToOperation _Operation;
        string _ComparisionPropertyName1;
        string _ComparisionPropertyName2;
    
        public CompareToAttribute(CompareToOperation operation, string comparisonPropertyName1, string comparisonPropertyName2)
        {
            _Operation = operation;
            _ComparisionPropertyName1 = comparisonPropertyName1;
            _ComparisionPropertyName2 = comparisonPropertyName2;
        }
    
        private static IComparable GetComparablePropertyValue(object obj, string propertyName)
        {
            if (obj == null) return null;
            var type = obj.GetType();
            var propertyInfo = type.GetProperty(propertyName);
            if (propertyInfo == null) return null;
            return propertyInfo.GetValue(obj, null) as IComparable;
        }
    
        public override bool IsValid(object value)
        {
            var comp1 = GetComparablePropertyValue(value, _ComparisionPropertyName1);
            var comp2 = GetComparablePropertyValue(value, _ComparisionPropertyName2);
    
            if (comp1 == null && comp2 == null)
                return true;
    
            if (comp1 == null || comp2 == null)
                return false;
    
            var result = comp1.CompareTo(comp2);
    
            switch (_Operation)
            {
                case CompareToOperation.LessThan: return result == -1;
                case CompareToOperation.EqualTo: return result == 0;
                case CompareToOperation.GreaterThan: return result == 1;
                default: return false;
            }
        }
    }
    
    [CompareTo(CompareToOperation.LessThan, "Start", "End")]
    public class SimpleClass
    {
        public DateTime Start { get; set; }
        public DateTime End { get; set; }
    }
    
        2
  •  14
  •   moi_meme    15 年前

    检查MVC2默认项目中的accountModel,将属性propertiesMustMatchAttribute应用于ChangePasswordModel,以验证newPassword和confirmPassword是否匹配。

       [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
    public sealed class PropertiesMustMatchAttribute : ValidationAttribute
    {
        private const string _defaultErrorMessage = "'{0}' and '{1}' do not match.";
    
        private readonly object _typeId = new object();
    
        public PropertiesMustMatchAttribute(string originalProperty, string confirmProperty)
            : base(_defaultErrorMessage)
        {
            OriginalProperty = originalProperty;
            ConfirmProperty = confirmProperty;
        }
    
        public string ConfirmProperty
        {
            get;
            private set;
        }
    
        public string OriginalProperty
        {
            get;
            private set;
        }
    
        public override object TypeId
        {
            get
            {
                return _typeId;
            }
        }
    
        public override string FormatErrorMessage(string name)
        {
            return String.Format(CultureInfo.CurrentUICulture, ErrorMessageString,
                OriginalProperty, ConfirmProperty);
        }
    
        public override bool IsValid(object value)
        {
            PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(value);
            object originalValue = properties.Find(OriginalProperty, true /* ignoreCase */).GetValue(value);
            object confirmValue = properties.Find(ConfirmProperty, true /* ignoreCase */).GetValue(value);
            return Object.Equals(originalValue, confirmValue);
        }
    }
    
        3
  •  0
  •   Mikeon    16 年前

    从表面上看,这是不可能的。

    validationAttribute应用于属性,因此仅限于该属性。

    我假设这个问题不是抽象的,并且您确实有一个真正的问题需要存在这样的验证器。可能是重复密码文本框?-)

    在任何情况下,要解决你所面临的问题,你需要依赖于你所处的环境。ASP.NET Web窗体使用ControlToCompare完成了这项工作,由于所有内容都是一个控件,而且我们有适当的命名容器,因此基于一个简单的字符串很容易解决问题。

    在ASP.NET MVC中,理论上可以做同样的事情,但是!客户端将相当容易和自然-只需使用属性名并用JavaScript完成您的工作。尽管您需要访问属性类外部的东西——请求对象——据我所知,这是一个否。

    总的来说,事情发生(没有)的原因总是存在的,在我看来,微软没有首先实现这种验证器的原因是——没有上面描述的事情是不可能的。

    但是!我真的希望我错了。我需要比较验证以便于使用…

        4
  •  0
  •   Jon Galloway    16 年前

    我想你需要这样的东西:

    public class EqualsAttribute : ValidationAttribute
    {
     private readonly String _To;
    
     public EqualsAttribute(String to)
     {
      if (String.IsNullOrEmpty(to))
      {
       throw new ArgumentNullException("to");
      }
      if (String.IsNullOrEmpty(key))
      {
       throw new ArgumentNullException("key");
      }
      _To = to;
     }
    
    
     protected override Boolean IsValid(Object value, ValidationContext validationContext, out ValidationResult validationResult)
     {
      validationResult = null;
      var isValid = IsValid(value, validationContext);
      if (!isValid)
      {
       validationResult = new ValidationResult(
        FormatErrorMessage(validationContext.DisplayName),
        new [] { validationContext.MemberName });
      }
      return isValid;
     }
    
     private Boolean IsValid(Object value, ValidationContext validationContext)
     {
      var propertyInfo = validationContext.ObjectType.GetProperty(_To);
      if (propertyInfo == null)
      {
       return false;
      }
      var propertyValue = propertyInfo.GetValue(validationContext.ObjectInstance, null);
      return Equals(value, propertyValue);
     }
    
     public override Boolean IsValid(Object value)
     {
      throw new NotSupportedException();
     }
    }