2010-09-24 9 views
0

J'utilise les attributs d'annotations de données pour la validation dans mon application, et je souhaite avoir un attribut RequiredAsSet qui nécessitera le remplissage de toutes les propriétés décorées avec l'attribut, ou aucune. L'ensemble ne peut pas être partiellement peuplé.Attribut de validation "RequiredAsSet"

Je pensais que d'une manière intelligente de le faire serait comme ceci:

public class RequiredAsSetAttribute : RequiredAttribute 
{ 
    /// <summary> 
    /// Initializes a new instance of the <see cref="RequiredAsSetAttribute"/> class. 
    /// </summary> 
    /// <param name="viewModel">The view model.</param> 
    public RequiredAsSetAttribute(IViewModel viewModel) 
    { 
     this.ViewModel = viewModel; 
    } 

    /// <summary> 
    /// Gets or sets the view model. 
    /// </summary> 
    /// <value>The view model.</value> 
    private IViewModel ViewModel { get; set; } 

    /// <summary> 
    /// Determines whether the specified value is valid. 
    /// </summary> 
    /// <param name="value">The value.</param> 
    /// <returns> 
    /// <c>true</c> if the specified value is valid; otherwise, <c>false</c>. 
    /// </returns> 
    public override bool IsValid(object value) 
    { 
     IEnumerable<PropertyInfo> properties = GetPropertiesWihRequiredAsSetAttribute(); 
     bool aValueHasBeenEnteredInTheRequiredFieldSet = properties.Any(property => !string.IsNullOrEmpty(property.GetValue(this.ViewModel, null).ToString())); 
     if (aValueHasBeenEnteredInTheRequiredFieldSet) 
     { 
      return base.IsValid(value); 
     } 

     return true; 
    } 

    /// <summary> 
    /// Gets the properties with required as set attribute. 
    /// </summary> 
    /// <returns></returns> 
    private IEnumerable<PropertyInfo> GetPropertiesWithRequiredAsSetAttribute() 
    { 
     return this.ViewModel.GetType() 
      .GetProperties() 
      .Where(p => GetValidatorsFromProperty(p).Length != 0 && !GetValidatorsFromProperty(p).Any(x => x == this));     
    } 

    /// <summary> 
    /// Gets the validators from property. 
    /// </summary> 
    /// <param name="property">The property.</param> 
    /// <returns></returns> 
    private static RequiredAsSetAttribute[] GetValidatorsFromProperty(PropertyInfo property) 
    { 
     return (RequiredAsSetAttribute[])property.GetCustomAttributes(typeof(RequiredAsSetAttribute), true); 
    } 
} 

Il prend essentiellement mon modèle de vue comme un argument du constructeur et utilise la réflexion pour trouver les autres propriétés décorées avec l'attribut RequiredAsSet pour vérifier si quelque chose a été entré. Il s'avère cependant que ce n'est pas une idée géniale, car vous ne pouvez pas passer des instances dans le constructeur d'un attribut ... uniquement des expressions constantes, des expressions de typeof ou des expressions de création de tableau, comme le compilateur l'a indiqué.

Y a-t-il une autre façon de procéder?

Répondre

0

Si je comprends bien le problème, la manière de le faire est avec un attribut de validation de niveau classe. Vous avez alors accès à l'ensemble de l'objet et pouvez utiliser la réflexion pour accéder aux propriétés souhaitées. L'instance est transmise lors de la validation.

[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)] 
public class RequiredAsSetAttribute : ValidationAttribute 
{ 
    public override bool IsValid(object value) 
    { 
     var properties = TypeDescriptor.GetProperties(value); 
     ... 
    } 
}