web-dev-qa-db-fra.com

Attribut MinValue & MaxValue pour les propriétés

Est-il possible de créer un attribut pouvant limiter la valeur minimale ou maximale des nombres.

Exemple:

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

et quand je fais Size = -3; la valeur de Size doit être 1.

J'ai cherché dans Google et je ne trouve pas un seul exemple concernant ce comportement, peut-être parce qu'il est impossible de le faire?

Je vais utiliser ces attributs dans la grille des propriétés. Par conséquent, la validation automatique peut être pratique.

Actuellement, je résous ce problème pour limiter la valeur minimale:

    private int size;

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

Donc, cela agit comme MinValue (1)

13
Jaex

Bien qu'il soit possible de créer un attribut personnalisé, les attributs ne sont que des métadonnées pour le membre qu'ils annotent et ne peuvent pas en modifier le comportement.

Donc, vous n'obtiendrez pas le comportement souhaité avec un attribut simple. Vous avez besoin de quelque chose pour traiter les attributs afin de mettre en œuvre le comportement souhaité.

Jetez un coup d'oeil à TypeConverters pour une possibilité.

4
Jordão

Vous pouvez résoudre ce problème avec élégance en utilisant PostSharp en écrivant un aspect simple, une version gratuite suffira à cela:

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

et puis exactement comme vous voulez:

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

avec une utilisation normale:

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

affichera 1.

4
Konrad Kokosa

Oui c'est possible. Lisez à propos des attributs personnalisés à MSDN .

Et au fait, il existe déjà une solution que vous pouvez utiliser. C'est la RangeAttribute qui vous permet de spécifier les contraintes de plage numérique pour la valeur d'un champ de données. En savoir plus à ce sujet sur MSDN .

2
Ondrej Janacek

Oui, il est possible avec CustomAttributes (déjà pointé), mais attention, vous perdrez le confort des propriétés automatiques - car vous devez appliquer resp. vérifiez la restriction d'attribut quelque part et dans ce cas un get approprié serait le getter de la propriété, donc la partie intéressante du problème est l'application des attributs. Vous pouvez lire comment accéder aux attributs personnalisés dans cet article MSDN

Une solution possible pour l'attribut personnalisé MaxValue peut ressembler à ceci:

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

L'utilisation de l'échantillon:

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

crée la sortie:

10

Le code de MinValue sera identique à celui de MaxValue mais la condition if sera inférieure à au lieu de supérieure à.

1
pasty

créer une extension

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

Et alors:

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