2009-08-26 8 views
3

Un exemple de classe dans le "Manuel de description de classe C#" (p. 137) n'appelle pas la méthode de validation des classes pour un champ spécifique à l'intérieur du constructeur des classes uniquement. Donc, fondamentalement, la classe d'échantillon vous permet de créer un objet avec de mauvaises données et ne lance une erreur que pour cette donnée lorsque vous appelez la propriété du champ qui la valide alors. Donc vous avez maintenant un mauvais objet et ne le savez pas après le fait.Validation des données du constructeur

Je n'ai jamais compris pourquoi ils n'appellent pas simplement la propriété du constructeur en lançant une erreur immédiatement si de mauvaises données sont trouvées pendant l'initialisation? Je les ai envoyé par e-mail en vain ...

J'ai tendance à utiliser le format suivant en appelant mes propriétés de mes constructeurs - est-ce la bonne structure pour valider les données d'initialisation? ty

class Foo 
{ 
    private string _emailAddress; 

    public Foo(string emailAddress) 
    { 
     EmailAddress = emailAddress; 
    } 

    public string EmailAddress 
    { 
     get { return _emailAddress; } 
     set 
     { 
      if (!ValidEmail(value)) 
       throw new ArgumentException 
        (string.Format 
        ("Email address {0} is in wrong format", 
        value)); 

      _emailAddress = value; 
     } 
    } 


    private static bool ValidEmail(string emailAddress) 
    { 
     return Regex.IsMatch 
      (emailAddress, @"\b[A-Z0-9._%+-]+" + 
          @"@[A-Z0-9.-]+\.[A-Z]{2,4}\b", 
          RegexOptions.IgnoreCase); 
    } 
} 
+0

Cela devrait probablement être une question de communauté - quelqu'un pourrait-il s'il vous plaît le régler correctement si c'est le cas. – user10178

Répondre

2

Eh bien, pour l'un, vous êtes susceptible d'obtenir le NullReferenceException redoutée, puisque vous n'êtes pas vérifier si emailAddress est nulle à tous les niveaux. Cette vérification particulière doit être effectuée dans le constructeur lui-même, et si emailAddress IS est nul, lancez une ArgumentNullException. Pour le reste, je ne vois pas de problèmes particuliers car il est écrit dans votre échantillon. Cependant, certains problèmes peuvent survenir si vous rendez la propriété virtuelle et dérivez des enfants de cette classe. L'ordre d'exécution de l'initialisation du champ, de la base et des consturceurs de classes dérivées devient alors un problème, et vous devez faire attention.

+0

Je l'ai laissé pour plus de clarté mais oui merci ... – user10178

+0

De rien. :) – jrista

0

Je ne vois rien de mal à cette approche. Vous pouvez appeler des méthodes sur ceci dans le constructeur, et les setters/getters de propriété sont juste du sucre syntaxique pour les appels de méthode.

+0

La classe se comporte différemment si l'adresse électronique est définie dans le constructeur par rapport à l'accesseur de propriété. Un comportement incohérent n'est pas une bonne propriété de conception :-) –

+0

dans l'exemple de code que le demandeur a demandé au constructeur d'utiliser le setter de propriétés aussi loin que je peux le dire, donc le comportement serait en fait cohérent. Y a-t-il quelque chose qui me manque? – Kevlar

2

Oui, si votre approche générale est:

Assurez-vous que vous ne pouvez obtenir une instance d'un objet valid

je l'aime.

Constructors doit être utilisé pour créer des objets qui sont immédiatement valides, ne pas créer juste un « contenant », des choses à mettre en.

+0

Oui, obtenir seulement des objets valides est l'idée ici - J'ajoute des surcharges du constructeur pour permettre aux utilisateurs d'entrer un champ vide où il est permis de le faire. ty. – user10178

0

la validation se produit lorsque l'adresse e-mail est définie. C'est là que vous le voulez parce que l'adresse e-mail pourrait éventuellement être définie à nouveau plus tard.

Si vous appeliez également la validation dans le constructeur, vous effectueriez un appel de validation supplémentaire et redondant (une fois lorsqu'il est construit, un autre lorsque l'adresse e-mail est définie dans le constructeur).

+0

Huh? Le paramètre d'origine de l'adresse e-mail est dans le constructeur qui appelle la propriété _emails. Si je viens de définir _email directement, j'aurais un mauvais objet si un mauvais email a été passé. Il ne serait validé que si la propriété a été modifiée après l'instanciation de l'objet. – user10178

+0

Le constructeur appelle le setter de la propriété: "EmailAddress" – apiguy

+0

Oui je comprends - je l'ai écrit. Ce que je n'ai pas compris, c'est que tu commentes ... désolé. – user10178

2

Cela n'a aucun sens pour moi de ne pas valider les données dans le constructeur. Comme vous le faites remarquer, l'objet peut finir dans un état invalide. Compte tenu de cette conception, vous ne réaliseriez même pas que vous aviez de mauvaises données lors de l'appel du getter.

Pour tout ce qui est de complexité moyenne ou supérieure, j'ai tendance à utiliser une approche Broken Rules plutôt que de lancer immédiatement une exception. Dans cette approche, je définis un objet BrokenRules qui contient des informations sur la classe et la propriété qui ne sont pas valides et la raison pour laquelle il est invalide. Ensuite, dans une classe de base commune, je définis une liste pour contenir une liste de tout "faux" à propos de l'objet. Une propriété (encore une fois dans la classe de base) IsValid indique s'il existe actuellement des règles brisées.

L'avantage de ceci est qu'il pourrait y avoir plusieurs problèmes avec l'état de l'objet. Si un utilisateur est invité à corriger les problèmes (c.-à-d.cet objet est défini à partir d'une interface utilisateur), fournissant une liste de tous les problèmes permet à l'utilisateur de les corriger en une seule fois, plutôt que de fixer une erreur juste pour être informé qu'il y en a un autre. Et un autre. Etc

+0

Merci Eric - Je me pencherai sur l'approche Broken Rules! Juste commencer à construire des cadres et encore apprendre. J'ai ramassé les «directives de conception de cadre» avec lesquelles je m'amuse! Grand livre. – user10178