Атрибут проверки "RequiredAsSet" - PullRequest
       11

Атрибут проверки "RequiredAsSet"

0 голосов
/ 24 сентября 2010

Я использую атрибуты аннотаций данных для проверки в своем приложении и хочу иметь атрибут RequiredAsSet, который потребует либо заполнения всех свойств, украшенных атрибутом, либо ни одного из них. Набор не может быть частично заполнен.

Я думал, что умный способ сделать это будет так:

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

Он в основном использует мою модель представления в качестве аргумента конструктора и использует отражение, чтобы найти другие свойства, украшенные атрибутом RequiredAsSet, чтобы проверить, было ли что-либо введено.

Оказывается, это не такая умная идея, потому что вы не можете передавать экземпляры в конструктор атрибута ... только константные выражения, выражения typeof или выражения создания массива, как подсказал компилятор.

Так есть ли другой способ сделать это?

1 Ответ

0 голосов
/ 24 сентября 2010

Если я правильно понимаю проблему, способ сделать это с помощью атрибута проверки уровня класса.Затем вы получаете доступ ко всему объекту и можете использовать отражение для доступа к любым свойствам, которые вы пожелаете.Экземпляр передается во время проверки.

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