Frage

Ich habe eine Situation, wo ich auf die Felder vergleichen möchten (beispielsweise ist vor der Endzeit die Startzeit zu gewährleisten). Ich verwende die System.ComponentModel.DataAnnotations Attribute für meine Validierung.

Mein erster Gedanke war so etwas wie folgt aus:

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

Dies gilt jedoch nicht funktioniert, gibt es einen Compiler-Fehler, wo das Attribut gekennzeichnet ist:

Expression cannot contain anonymous methods or lambda expressions

Ist dies eine Lösung jemand? Oder einen anderen Ansatz für die Validierung eines Feldes im Vergleich zu dem Wert eines anderen?

War es hilfreich?

Lösung

sehr hässliche Art und Weise, die nicht annähernd so flexibel ist, ist es für die Klasse und Reflexion zu nutzen. Ich habe nicht getestet, also bin ich nicht wirklich sicher, dass es funktioniert, aber es funktioniert kompilieren:)

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

Andere Tipps

Überprüfen Sie das AccountMOdel im Standard-Projekt von MVC2, Es ist ein Attribut PropertiesMustMatchAttribute auf die ChangePasswordModel angewendet zu bestätigen, dass die NewPassword und ConfirmPassword Spiel

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

Aus dem Blick von ihm, dies nicht getan werden kann.

Validation auf eine Eigenschaft angewendet wird, und als solche ist nur auf diese Eigenschaft beschränkt.

Ich nehme an, die Frage ist nicht eine abstrakte ein und Sie haben zu tun ein echtes Problem, das das Vorhandensein eines solchen Validator erfordert. Wahrscheinlich ist es die Wiederholung Passwort Textbox? : -)

Auf jeden Fall zu arbeiten, um das Problem Sie haben Sie auf den Kontext verlassen, in dem Sie arbeiten. ASP.NET Web Forms tat es mit der ControlToCompare und da alles, was eine Kontrolle ist, und wir haben Behälter an Ort und Stelle zu benennen, es ist ziemlich einfache Dinge, um herauszufinden, basiert auf einem einfachen String.

In ASP.NET MVC können Sie theoretisch das gleiche tun, ABER! Client-Seite wird ziemlich leicht und natürlich - nur die #PropertyName nutzen und tun Sie Ihre Sachen in Javascript. Serverside obwohl würden Sie etwas außerhalb Ihrer Attributklasse zugreifen müssen - das Request-Objekt - und das ist ein nein nein, so weit es mich betrifft

.

Alles in allem gibt es immer einen Grund für Dinge (nicht) passiert, und meiner Meinung nach ist ein Grund, warum Microsoft nicht diese Art von Validator in einem ersten Platz geführt hat - es nicht möglich ist, oben ohne Dinge beschrieben.

ABER! Ich hoffe wirklich, dass ich falsch bin. Ich brauche die vergleichen Validierung einfach zu bedienen ...

Ich glaube, Sie so etwas wie dieses brauchen:

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();
 }
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top