web-dev-qa-db-fra.com

Quelle exception à lever d'un poseur de propriété?

J'ai une propriété de chaîne qui a une exigence de longueur maximale car les données sont liées à une base de données. Quelle exception dois-je lever si l'appelant tente de définir une chaîne dépassant cette longueur?

Par exemple, ce code C #:

public string MyProperty
{
    get
    {
        return _MyBackingField;
    }
    set
    {
        if (value.Length > 100)
            throw new FooException("MyProperty has a maximum length of 100.");

        _MyBackingField = value;
    }
}

J'ai envisagé ArgumentException, mais cela ne semble pas juste. Techniquement, c'est une fonction - MyProperty_set(string value) - donc un cas pour ArgumentException peut être fait, mais il n'est pas appelé comme une fonction aux yeux du consommateur - c'est sur le côté droit d'un opérateur d'affectation.

Cette question pourrait probablement également être étendue pour inclure toutes sortes de validations de données effectuées dans les setters de propriétés, mais je suis particulièrement intéressé par le cas ci-dessus.

49
lc.

Jetez un œil à mscorlib.dll avec Reflector, dans une situation similaire telle que System.String.StringBuilder.Capacity Microsoft utilise ArgumentOutOfRangeException () similaire à:

public int PropertyA
{
    get
    {
        return //etc...
    }
    set
    {
        if (condition == true)
        {
            throw new ArgumentOutOfRangeException("value", "/* etc... */");
        }
        // ... etc
    }
}
46
Richard Slater

Pour moi, ArgumentException (ou un enfant) a plus de sens, car l'argument (valeur) que vous avez fourni n'est pas valide, et c'est pour cela que ArgumentException a été créé.

16
Davide Vosti

Je ne ferais pas du tout une exception. J'autoriserais plutôt une chaîne de n'importe quelle longueur et j'aurais ensuite une méthode distincte "Valider" sur la classe qui est appelée avant d'enregistrer. Il existe un certain nombre de scénarios, en particulier si vous utilisez la liaison de données où le fait de lever des exceptions de la part des setters de propriété peut vous mettre dans le pétrin.

Le problème avec le lancement d'exceptions de la part des setters de propriété est que les programmeurs oublient de les attraper. Cela dépend en quelque sorte de la propreté que vous attendez des données que vous obtenez. Dans ce cas, je m'attendrais à ce que les longues longueurs de chaîne soient communes et non exceptionnelles et en tant que tel, l'utilisation d'une exception serait un "contrôle de flux avec exceptions".

Pour citer les directives de conception de Microsoft pour le développement de bibliothèques de classes :

N'utilisez pas d'exceptions pour le flux normal de contrôle, si possible. À l'exception des défaillances du système et des opérations avec des conditions de concurrence potentielles, les concepteurs de framework doivent concevoir des API afin que les utilisateurs puissent écrire du code qui ne lève pas d'exceptions. Par exemple, vous pouvez fournir un moyen de vérifier les conditions préalables avant d'appeler un membre afin que les utilisateurs puissent écrire du code qui ne lève pas d'exceptions.

10
Martin Brown

Rappelez-vous combien de problèmes en informatique sont résolus en ajoutant un niveau supplémentaire d'indirection?

Une approche serait de créer un nouveau type, FixedLengthString, par exemple. Ce serait des instances du type that qui valident les longueurs de chaînes avec lesquelles elles sont initialisées - avec un opérateur de conversion pour effectuer une conversion de type à partir d'une chaîne simple. Si votre créateur de propriétés prend un tel type comme argument, toute violation deviendrait une exception de conversion de type au lieu d'une exception d'argument/de propriété.

En pratique, je ferais rarement cela. Cela sent un peu prendre OO trop loin - mais dans certains cas, cela peut être une technique utile, alors je la mentionne ici pour être complète.

6
philsquared
public IPAddress Address
{
    get
    {
        return address;
    }
    set
    {
        if(value == null)
        {
            throw new ArgumentNullException("value");
        }
        address = value;
    }
}

via MSDN

5
javros