Атрибут MinValue & MaxValue для свойств

можно ли сделать атрибут, который может ограничить минимальное или максимальное значение чисел.

пример:

[MinValue(1), MaxValue(50)]
public int Size { get; set; }

и когда я делаю Size = -3; стоимостью Size должен быть 1.

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

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

В настоящее время я обходной путь, как это для ограничения минимального значения:

    private int size;

    [DefaultValue(8)]
    public int Size
    {
        get
        {
            return size;
        }
        set
        {
            size = Math.Max(value, 1);
        }
    }

таким образом, это действует как MinValue (1)

5 ответов


хотя можно создать пользовательский атрибут, атрибуты являются только метаданными для элемента, который они аннотируют, и не могут изменить его поведение.

таким образом, вы не получите поведение, которое хотите с простым атрибутом. Вам нужно что-то обработать атрибуты, чтобы выполнить желаемое поведение.

посмотри TypeConverters Для возможность.


вы можете элегантно решить эту проблему, используя PostSharp написав простой аспект, бесплатная версия будет достаточно для этой цели:

[Serializable]
class RangeAttribute : LocationInterceptionAspect 
{
    private int min;
    private int max;

    public RangeAttribute(int min, int max)
    {
        this.min = min;
        this.max = max;
    }

    public override void OnSetValue(LocationInterceptionArgs args)
    {
        int value = (int)args.Value;
        if (value < min) value = min;
        if (value > max) value = max;            
        args.SetNewValue(value);
    }
}

и тогда точно, как вы хотите:

class SomeClass
{
    [Range(1, 50)]
    public int Size { get; set; }
}

с нормальным использованием:

var c = new SomeClass();
c.Size = -3;
Console.Output(c.Size);

будет выдавать 1.


Да, это возможно. Читайте о пользовательских атрибутах в MSDN.

и, кстати, уже есть решение, которое вы можете использовать. Это RangeAttribute что позволяет указать ограничения числового диапазона для значения поля данных. Подробнее об этом читайте на MSDN.


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

возможное решение для Пользовательский атрибут MaxValue может выглядеть следующим образом:

// simple class for the example
public class DataHolder
{
    private int a;

    [MaxValue(10)]
    public int A 
    { 
        get
        {
            var memberInfo = this.GetType().GetMember("A");
            if (memberInfo.Length > 0)
            {
                // name of property could be retrieved via reflection
                var mia = this.GetType().GetMember("A")[0];
                var attributes = System.Attribute.GetCustomAttributes(mia);
                if (attributes.Length > 0)
                {
                    // TODO: iterate over all attributes and check attribute name
                    var maxValueAttribute = (MaxValue)attributes[0];
                    if (a > maxValueAttribute.Max) { a = maxValueAttribute.Max; }
                }
            }
            return a;
        }
        set
        {
            a = value;
        }
    }
}


// max attribute
public class MaxValue : Attribute
{
    public int Max;

    public MaxValue(int max)
    {
        Max = max;  
    }
}

пример использования:

var data = new DataHolder();
data.A = 12;
Console.WriteLine(data.A);

создает на выходе:

10

код для MinValue будет выглядеть так же, как для MaxValue, но условие if будет меньше вместо больше.


создать расширение

public static class Extensions
{
  public static int FixedValue(this int value, int min, int max)
  {
    if (value >= min && value <= max)
      return value;
    else if (value > max)
      return max;
    else if (value < min)
      return min;
    else return 1;
  }
}

и затем:

private int size;
public int Size { get { return size.FixedValue(1, 50); }
                  set { size = value.FixedValue(1, 50); } }