문제

필드와 비교하고 싶은 상황이 있습니다 (예 : 시작 시간이 종료 시간이되기 전에). 나는 사용하고있다 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

누구든지 이것에 대한 해결책이 있습니까? 아니면 다른 필드를 검증하기위한 다른 접근법은 다른 필드의 값에 비해 다른 접근법입니까?

도움이 되었습니까?

해결책

매우 거의 유연하지 않은 못생긴 방법은 클래스에 넣고 반사를 사용하는 것입니다. 나는 이것을 테스트하지 않았으므로 실제로 그것이 작동하는지 확실하지 않지만 컴파일합니다 :)

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; }
}

다른 팁

MVC2의 기본 프로젝트에서 Acc

   [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);
    }
}

그것의 모양에서, 이것은 할 수 없습니다.

유효성 검사는 속성에 적용되며 해당 속성으로만 제한됩니다.

나는 질문이 추상적 인 것이 아니라고 가정하고 당신은 그러한 유효성 검사기의 존재를 요구하는 실제 문제가 있습니다. 아마도 반복 암호 텍스트 상자일까요? :-)

어쨌든, 문제를 해결하려면 당신이 일하는 맥락에 의존해야합니다. 간단한 문자열을 기반으로합니다.

ASP.NET MVC에서는 이론적으로 똑같은 일을 할 수 있지만! 클라이언트 측은 상당히 쉽고 자연 스럽습니다. #PropertyName을 사용하고 JavaScript로 작업을 수행하십시오. serverside는 속성 클래스 외부에 액세스해야하지만 요청 객체입니다. 이는 내가 염려하는 한 아닙니다.

대체로, 항상 일이 일어나지 않는 이유가 있으며, 제 생각에는 Microsoft가 이러한 종류의 유효성 검사기를 먼저 구현하지 않은 이유는 위에서 설명한 것들 없이는 불가능합니다.

하지만! 정말 내가 틀렸기를 바랍니다. 사용하기 쉬운 비교 검증이 필요합니다 ...

나는 당신이 다음과 같은 것이 필요하다고 생각합니다.

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();
 }
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top