Запись атрибута CompareTo DataAnnotation

Как со всем, это - все об оценке ситуации. В DotNetNuke там является довольно базовым компонентом, названным FillObject, который использует отражение для заполнения объектов от datarows.

Это - довольно общий сценарий и существует статья о MSDN, Используя Отражение для Привязки Бизнес-объектов со Средствами управления Формой ASP.NET , который охватывает проблемы производительности.

Производительность в стороне, одна вещь мне не нравится приблизительно использовать отражение, в котором конкретный сценарий - то, что это имеет тенденцию уменьшать способность понять код на быстрый взгляд, который для меня не кажется стоящим усилия, когда Вы полагаете, что также теряете безопасность времени компиляции в противоположность наборам данных со строгим контролем типов или чему-то как LINQ  to  SQL.

9
задан Kirschstein 22 October 2009 в 14:58
поделиться

4 ответа

A очень уродливый способ, который не так уж и гибко, это поставить его на класс и использовать отражение. Я не тестировал это, так что на самом деле не уверен, что это работает, но он компилирует :)

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; }
}
8
ответ дан 4 December 2019 в 09:37
поделиться

Судя по всему, это невозможно.

Атрибут ValidationAttribute применяется к свойству и поэтому ограничен этим только свойство.

Я полагаю, что вопрос не является абстрактным, и у вас действительно есть реальная проблема, требующая наличия такого валидатора. Возможно, это текстовое поле для повторного ввода пароля? : -)

В любом случае, чтобы обойти возникшую у вас проблему, вам нужно полагаться на контекст, в котором вы работаете. Веб-формы ASP.NET сделали это с помощью ControlToCompare, и поскольку все является элементом управления, и у нас есть имена контейнеров в place довольно легко разобраться, основываясь на простой строке.

В ASP.NET MVC теоретически вы можете делать то же самое, НО! Клиентская часть будет довольно простой и естественной - просто используйте #PropertyName и делайте свои вещи на javascript. На стороне сервера вам понадобится доступ к чему-то внешнему по отношению к вашему классу атрибутов - объекту Request - и это, насколько я понимаю, нет.

В общем, всегда есть причина, по которой что-то (не) происходит и, на мой взгляд, причина, по которой Microsoft не реализовала этот тип валидатора в первую очередь, заключается в том, что это невозможно без вещей, описанных выше.

НО! Я очень надеюсь, что ошибаюсь. Мне ДЕЙСТВИТЕЛЬНО нужна проверка сравнения, чтобы ее было легко использовать ...

Причина, по которой Microsoft не реализовала этот тип валидатора в первую очередь, - это невозможно без вещей, описанных выше.

НО! Я очень надеюсь, что ошибаюсь. Мне ДЕЙСТВИТЕЛЬНО нужна проверка сравнения, чтобы ее было легко использовать ...

Причина, по которой Microsoft не реализовала этот тип валидатора в первую очередь, - это невозможно без вещей, описанных выше.

НО! Я очень надеюсь, что ошибаюсь. Мне НЕОБХОДИМО, чтобы проверка сравнения была простой в использовании ...

0
ответ дан 4 December 2019 в 09:37
поделиться

Я думаю, вам понадобится что-то вроде этого:

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();
 }
}
0
ответ дан 4 December 2019 в 09:37
поделиться

Проверьте AccountMOdel в проекте по умолчанию MVC2. К ChangePasswordModel применен атрибут PropertiesMustMatchAttribute для проверки совпадения 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);
    }
}
14
ответ дан 4 December 2019 в 09:37
поделиться
Другие вопросы по тегам:

Похожие вопросы: