Pourquoi devrais-je éviter d'utiliser des propriétés en C #?

102

Dans son excellent livre, CLR Via C #, Jeffrey Richter a déclaré qu'il n'aime pas les propriétés et recommande de ne pas les utiliser. Il a donné une raison, mais je ne comprends pas vraiment. Quelqu'un peut-il m'expliquer pourquoi je devrais ou ne devrais pas utiliser des propriétés? En C # 3.0, avec les propriétés automatiques, cela change-t-il?

À titre de référence, j'ai ajouté les opinions de Jeffrey Richter:

• Une propriété peut être en lecture seule ou en écriture seule; l'accès aux champs est toujours lisible et inscriptible. Si vous définissez une propriété, il est préférable de proposer à la fois des méthodes d'accesseur get et set.

• Une méthode de propriété peut lever une exception; l'accès aux champs ne lève jamais d'exception.

• Une propriété ne peut pas être transmise en tant que paramètre out ou ref à une méthode; un champ peut. Par exemple, le code suivant ne sera pas compilé:

using System;
public sealed class SomeType
{
   private static String Name 
   {
     get { return null; }
     set {}
   }
   static void MethodWithOutParam(out String n) { n = null; }
   public static void Main()
   {
      // For the line of code below, the C# compiler emits the following:
      // error CS0206: A property or indexer may not
      // be passed as an out or ref parameter
      MethodWithOutParam(out Name);
   }
}

• Une méthode de propriété peut prendre un certain temps à s'exécuter; l'accès au champ se termine toujours immédiatement. Une raison courante d'utiliser des propriétés est d'effectuer la synchronisation des threads, ce qui peut arrêter le thread pour toujours, et par conséquent, une propriété ne doit pas être utilisée si la synchronisation des threads est requise. Dans cette situation, une méthode est préférée. En outre, si votre classe est accessible à distance (par exemple, votre classe est dérivée de System.MashalByRefObject), l'appel de la méthode de propriété sera très lent et, par conséquent, une méthode est préférée à une propriété. À mon avis, les classes dérivées de MarshalByRefObject ne devraient jamais utiliser de propriétés.

• Si elle est appelée plusieurs fois de suite, une méthode de propriété peut renvoyer une valeur différente à chaque fois; un champ renvoie la même valeur à chaque fois. La classe System.DateTime a une propriété en lecture seule Now qui renvoie la date et l'heure actuelles. Chaque fois que vous interrogez cette propriété, elle renvoie une valeur différente. C'est une erreur, et Microsoft souhaite pouvoir corriger la classe en faisant de Now une méthode au lieu d'une propriété.

• Une méthode de propriété peut provoquer des effets secondaires observables; l'accès sur le terrain ne le fait jamais. En d'autres termes, un utilisateur d'un type doit être capable de définir diverses propriétés définies par un type dans n'importe quel ordre de son choix sans remarquer aucun comportement différent dans le type.

• Une méthode de propriété peut nécessiter de la mémoire supplémentaire ou renvoyer une référence à quelque chose qui ne fait pas réellement partie de l'état de l'objet, donc la modification de l'objet retourné n'a aucun effet sur l'objet d'origine; l'interrogation d'un champ renvoie toujours une référence à un objet dont il est garanti qu'il fait partie de l'état de l'objet d'origine. Travailler avec une propriété qui renvoie une copie peut être très déroutant pour les développeurs, et cette caractéristique n'est souvent pas documentée.

Quan Mai
la source
11
Je possède la 3e édition de 'CLR via C #' et à la page 242, M. Richter dit qu'il n'aime pas personnellement les propriétés, mais il ne recommande jamais de ne pas les utiliser. Veuillez citer la version du livre et le numéro de page où vous avez lu ceci.
kirk.burleson

Réponses:

173

La raison pour laquelle Jeff n'aime pas les propriétés est qu'elles ressemblent à des champs - donc les développeurs qui ne comprennent pas la différence les traiteront comme s'il s'agissait de champs, en supposant qu'ils seront bon marché à exécuter, etc.

Personnellement, je ne suis pas d'accord avec lui sur ce point particulier - je trouve que les propriétés rendent le code client beaucoup plus simple à lire que les appels de méthode équivalents. Je conviens que les développeurs doivent savoir que les propriétés sont essentiellement des méthodes déguisées - mais je pense qu'éduquer les développeurs à ce sujet est mieux que de rendre le code plus difficile à lire à l'aide de méthodes. (En particulier, ayant vu du code Java avec plusieurs getters et setters appelés dans la même instruction, je sais que le code C # équivalent serait beaucoup plus simple à lire. La loi de Demeter est très bien en théorie, mais parfois foo.Name.Lengthest vraiment la bonne chose à utiliser ...)

(Et non, les propriétés implémentées automatiquement ne changent rien de tout cela.)

C'est un peu comme les arguments contre l'utilisation des méthodes d'extension - je peux comprendre le raisonnement, mais l'avantage pratique (lorsqu'il est utilisé avec parcimonie) l'emporte sur l'inconvénient à mon avis.

Jon Skeet
la source
Merci beaucoup pour votre réponse! À propos des arguments contre l'utilisation des méthodes d'extension: parlez-vous d'un sujet de Jeffrey Richter ou en résumé?
abatishchev
@abatishchev: C'était juste un point général sur les méthodes d'extension. Ce n'est pas directement lié aux propriétés.
Jon Skeet
J'irais plus loin. A part l'aspect performance, je ne vois pas pourquoi un programmeur devrait SAVOIR si quelque chose est un champ ou une propriété. Il devrait le considérer comme un attribut d'instance désignant l'état de l'instance d'objet, et l'implémentation de l'objet devrait prendre en charge toutes les modifications de son état (dans le contrat de la classe). Ainsi, les propriétés pourraient tout aussi bien être des champs dans certains cas, ou devenir des champs dans d'autres, si peut-être une refonte de l'implémentation de la classe est effectuée. Ensuite, décider entre un champ ou une propriété dépend du niveau de protection dont l'État a besoin pour rester cohérent.
TheBlastOne
1
@PatrickFromberg: Vous avez manqué une grande quantité de code qui utilise des champs en lecture seule, apparemment. Rien ne dit que les propriétés impliquent la mutabilité. J'ai souvent des champs en lecture seule soutenant des propriétés en lecture seule - pensez-vous que ce soit une mauvaise chose?
Jon Skeet
1
@Patrick: Non, cela apporte l'avantage de séparer l'API de l'implémentation - vous pouvez plus tard modifier la façon dont la propriété est calculée à partir du champ (par exemple pour calculer deux propriétés liées à partir d'un champ).
Jon Skeet
34

Eh bien, prenons ses arguments un par un:

Une propriété peut être en lecture seule ou en écriture seule; l'accès aux champs est toujours lisible et inscriptible.

C'est une victoire pour les propriétés, car vous disposez d'un contrôle d'accès plus fin.

Une méthode de propriété peut lever une exception; l'accès aux champs ne lève jamais d'exception.

Bien que cela soit généralement vrai, vous pouvez très bien appeler une méthode sur un champ objet non initialisé et faire lever une exception.

• Une propriété ne peut pas être transmise en tant que paramètre out ou ref à une méthode; un champ peut.

Juste.

• Une méthode de propriété peut prendre un certain temps à s'exécuter; l'accès au champ se termine toujours immédiatement.

Cela peut également prendre très peu de temps.

• Si elle est appelée plusieurs fois de suite, une méthode de propriété peut renvoyer une valeur différente à chaque fois; un champ renvoie la même valeur à chaque fois.

Pas vrai. Comment savez-vous que la valeur du champ n'a pas changé (peut-être par un autre thread)?

La classe System.DateTime a une propriété en lecture seule Now qui renvoie la date et l'heure actuelles. Chaque fois que vous interrogez cette propriété, elle renvoie une valeur différente. C'est une erreur, et Microsoft souhaite pouvoir corriger la classe en faisant de Now une méthode au lieu d'une propriété.

Si c'est une erreur, c'est mineure.

• Une méthode de propriété peut provoquer des effets secondaires observables; l'accès sur le terrain ne le fait jamais. En d'autres termes, un utilisateur d'un type doit être capable de définir diverses propriétés définies par un type dans n'importe quel ordre de son choix sans remarquer aucun comportement différent dans le type.

Juste.

• Une méthode de propriété peut nécessiter de la mémoire supplémentaire ou renvoyer une référence à quelque chose qui ne fait pas réellement partie de l'état de l'objet, donc la modification de l'objet retourné n'a aucun effet sur l'objet d'origine; l'interrogation d'un champ renvoie toujours une référence à un objet dont il est garanti qu'il fait partie de l'état de l'objet d'origine. Travailler avec une propriété qui renvoie une copie peut être très déroutant pour les développeurs, et cette caractéristique n'est souvent pas documentée.

La plupart des protestations pourraient également concerner les getters et les setters de Java - et nous les avons eues pendant un bon moment sans de tels problèmes dans la pratique.

Je pense que la plupart des problèmes pourraient être résolus par une meilleure coloration syntaxique (c'est-à-dire en différenciant les propriétés des champs) afin que le programmeur sache à quoi s'attendre.

Hejazzman
la source
3
"les problèmes pourraient être résolus par une meilleure coloration syntaxique" : à quelle fréquence utilisez-vous les champs publics? Les champs privés ont généralement un style différent, par exemple _field. Ou même simplement en minuscules field.
Steven Jeuris
18

Je n'ai pas lu le livre et vous n'en avez pas cité la partie que vous ne comprenez pas, alors je vais devoir deviner.

Certaines personnes n'aiment pas les propriétés car elles peuvent amener votre code à faire des choses surprenantes.

Si je tape Foo.Bar, les gens qui le liront s'attendront normalement à ce qu'il accède simplement à un champ membre de la classe Foo. C'est une opération bon marché, presque gratuite et déterministe. Je peux l'appeler encore et encore et obtenir le même résultat à chaque fois.

Au lieu de cela, avec les propriétés, il peut s'agir d'un appel de fonction. Ce pourrait être une boucle infinie. Cela pourrait ouvrir une connexion à la base de données. Il peut renvoyer des valeurs différentes chaque fois que j'y accède.

C'est un argument similaire pour expliquer pourquoi Linus déteste le C ++. Votre code peut surprendre le lecteur. Il déteste la surcharge des opérateurs: a + bne signifie pas nécessairement un simple ajout. Cela peut signifier une opération extrêmement compliquée, tout comme les propriétés C #. Cela peut avoir des effets secondaires. Cela peut faire n'importe quoi.

Honnêtement, je pense que c'est un argument faible. Les deux langues regorgent de choses comme celle-ci. (Devrions-nous éviter la surcharge d'opérateurs en C # également? Après tout, le même argument peut être utilisé ici)

Les propriétés permettent l'abstraction. Nous pouvons prétendre que quelque chose est un domaine normal, l'utiliser comme s'il en était un, sans avoir à nous soucier de ce qui se passe dans les coulisses.

C'est généralement considéré comme une bonne chose, mais cela repose évidemment sur l'écriture d'abstractions significatives par le programmeur. Vos propriétés doivent se comporter comme des champs. Ils ne devraient pas avoir d'effets secondaires, ils ne devraient pas effectuer d'opérations coûteuses ou dangereuses. Nous voulons pouvoir les considérer comme des champs.

Cependant, j'ai une autre raison de les trouver moins que parfaites. Ils ne peuvent pas être transmis par référence à d'autres fonctions.

Les champs peuvent être passés comme ref, permettant à une fonction appelée d'y accéder directement. Les fonctions peuvent être passées en tant que délégués, permettant à une fonction appelée d'y accéder directement.

Les propriétés ... ne peuvent pas.

Ça craint.

Mais cela ne signifie pas que les propriétés sont mauvaises ou ne doivent pas être utilisées. À de nombreuses fins, ils sont excellents.

jalf
la source
3
Mon argument est que vous ne devriez pas supposer que c'est un champ pour commencer - parce que si vous l'appelez à partir d'une autre classe, vous ne devriez pas avoir accès aux champs non constants de toute façon, car ils devraient être privés. (Il y a aussi la convention de dénomination pour vous informer.)
Jon Skeet
1
Oui je suis d'accord. L'argument semble se résumer à "Je suis habitué à ce que cette syntaxe soit utilisée uniquement pour les champs. Par conséquent, l'étendre pour couvrir d'autres cas est mauvais". Et la réponse évidente est "Eh bien, habituez-vous à couvrir d'autres cas, et ce ne sera pas mal". ;)
jalf
Je souhaite que les langages .net fournissent un moyen standard par lequel une classe expose des propriétés en tant que refparamètres; un membre (par exemple Foo) d'un formulaire void Foo<T>(ActionByRef<Point,T> proc, ref T param)avec un attribut spécial, et faire transformer le compilateur thing.Foo.X+=someVar;en Foo((ref Point it, ref int param)=>it.X += param, ref someVar);. Puisque le lambda est un délégué statique, aucune fermeture ne serait requise, et l'utilisateur d'un objet pourrait utiliser n'importe quel emplacement de stockage sauvegardé la propriété en tant que refparamètre authentique (et pourrait le transmettre à d'autres méthodes en tant que refparamètre).
supercat
L'écriture manuelle du lambda produit un code source vraiment dégoûtant, mais c'est pourquoi il serait utile que le compilateur effectue la transformation. Le code d'une classe pour exposer une propriété "callback-by-ref" serait assez raisonnable. Le code est seulement moche (sans transformation) du côté de l'appelant.
supercat du
Veuillez comprendre qu'une propriété est un appel de fonction déguisé en membre, donc elle ne peut pas être passée par référence pas plus que vous ne pouvez transmettre les fonctions publiques d'une classe. Vous pouvez toujours utiliser un membre public si vous avez l'intention de le faire de cette façon. Une propriété est un membre intelligent, elle peut lever une exception pour les données non valides transmises à set.
Diceyus
17

En 2009, ce conseil ressemblait simplement à la variété Who Moved My Cheese . Aujourd'hui, c'est presque ridiculement obsolète.

Un point très important que de nombreuses réponses semblent sur la pointe des pieds mais qui ne sont pas tout à fait abordés de front est que ces prétendus «dangers» des propriétés font intentionnellement partie de la conception du cadre!

Oui, les propriétés peuvent:

  • Spécifiez différents modificateurs d'accès pour le getter et le setter. C'est un avantage par rapport aux champs. Un modèle courant est d'avoir un getter public et un setter protégé ou interne , une technique d'héritage très utile qui n'est pas réalisable par des champs seuls.

  • Lancez une exception. À ce jour, cela reste l'une des méthodes de validation les plus efficaces, en particulier lorsque vous travaillez avec des cadres d'interface utilisateur qui impliquent des concepts de liaison de données. Il est beaucoup plus difficile de garantir qu'un objet reste dans un état valide lorsque vous travaillez avec des champs.

  • Prenez beaucoup de temps à exécuter. La comparaison valable ici est avec les méthodes , qui prennent tout aussi longtemps - pas les champs . Aucune base n'est donnée pour la déclaration «une méthode est préférée» autre que la préférence personnelle d'un auteur.

  • Renvoie des valeurs différentes de son getter lors des exécutions suivantes. Cela ressemble presque à une blague si proche du point vantant les vertus de ref/ outparameters avec des champs, dont la valeur d'un champ après un appel ref/ outest à peu près garantie d'être différente de sa valeur précédente, et de manière imprévisible.

    Si nous parlons du cas spécifique (et pratiquement académique) de l'accès monotrou sans accouplements afférents, c'est assez bien entendu que c'est juste une mauvaise conception de propriété d'avoir des effets secondaires de changement d'état visible, et peut-être que ma mémoire est décoloration, mais je n'arrive tout simplement pas à me souvenir d'exemples de personnes utilisant DateTime.Nowet s'attendant à ce que la même valeur ressorte à chaque fois. Du moins, pas de cas où ils n'auraient pas tout foiré avec un hypothétique DateTime.Now().

  • Causer des effets secondaires observables - ce qui est bien sûr précisément la raison pour laquelle les propriétés ont été inventées en tant que caractéristique du langage en premier lieu. Propre à Microsoft directives de conception de propriétés de indiquent que l'ordre des passeurs ne devrait pas avoir d'importance, car faire autrement impliquerait un couplage temporel . Certes, vous ne pouvez pas réaliser un couplage temporel avec des champs seuls, mais c'est uniquement parce que vous ne pouvez pas provoquer de comportement significatif avec des champs seuls, jusqu'à ce qu'une méthode soit exécutée.

    Les accesseurs de propriété peuvent en fait aider à empêcher certains types de couplage temporel en forçant l'objet dans un état valide avant qu'une action ne soit entreprise - par exemple, si une classe a un StartDateet un EndDate, alors définir le EndDateavant le StartDatepourrait également forcer le StartDateretour. Cela est vrai même dans les environnements multithreads ou asynchrones, y compris l'exemple évident d'une interface utilisateur événementielle.

Autres choses que les propriétés peuvent faire et que les champs ne peuvent pas inclure:

  • Le chargement différé , l'un des moyens les plus efficaces de prévenir les erreurs d'ordre d'initialisation.
  • Notifications de changement , qui constituent à peu près toute la base de l' architecture MVVM .
  • Héritage , par exemple définir un résuméType ou des Nameclasses dérivées, peut fournir des métadonnées intéressantes mais néanmoins constantes sur elles-mêmes.
  • Interception , grâce à ce qui précède.
  • Indexeurs , que tous ceux qui ont déjà eu à travailler avec l'interopérabilité COM et l'inévitable crachat d' Item(i)appels reconnaîtront comme une chose merveilleuse.
  • Travailler avec PropertyDescriptor qui est essentiel pour créer des concepteurs et pour les frameworks XAML en général.

Richter est clairement un auteur prolifique et en sait beaucoup sur le CLR et le C #, mais je dois dire qu'il semble que lorsqu'il a écrit ce conseil à l'origine (je ne suis pas sûr que ce soit dans ses révisions les plus récentes - j'espère sincèrement que non) qu'il ne voulait tout simplement pas abandonner ses vieilles habitudes et avait du mal à accepter les conventions de C # (contre C ++, par exemple).

Ce que je veux dire par là, c'est que son argument «propriétés considérées comme nuisibles» se résume essentiellement à une seule déclaration: les propriétés ressemblent à des champs, mais elles peuvent ne pas agir comme des champs. Et le problème avec cette déclaration est que ce n'est pas vrai ou, au mieux, c'est très trompeur. Les propriétés ne ressemblent pas à des champs - du moins, elles ne sont pas censées ressembler à des champs.

Il existe deux conventions de codage très fortes en C # avec des conventions similaires partagées par d'autres langages CLR, et FXCop vous criera dessus si vous ne les suivez pas:

  1. Les champs doivent toujours être privés, jamais publics.
  2. Les champs doivent être déclarés dans camelCase. Les propriétés sont PascalCase.

Ainsi, il n'y a aucune ambiguïté quant à savoir s'il Foo.Bar = 42s'agit d'un accesseur de propriété ou d'un accesseur de champ. C'est un accesseur de propriété et devrait être traité comme n'importe quelle autre méthode - cela pourrait être lent, cela pourrait lever une exception, etc. C'est la nature d' Abstraction - c'est à la discrétion de la classe déclarante de savoir comment réagir. Les concepteurs de classe doivent appliquer le principe de la moindre surprise, mais les appelants ne doivent rien supposer d'une propriété, sauf qu'elle fait ce qu'elle dit sur l'étain. C'est exprès.

L'alternative aux propriétés est des méthodes getter / setter partout. C'est l'approche Java, et elle est controversée depuis le début . C'est bien si c'est votre sac, mais ce n'est tout simplement pas comme ça que nous roulons dans le camp .NET. Nous essayons, au moins dans les limites d'un système à typage statique, d'éviter ce que Fowler appelle Syntactic Noise . Nous ne voulons pas de parenthèses supplémentaires, d'extra get/ setwarts ou de signatures de méthode supplémentaires - pas si nous pouvons les éviter sans perte de clarté.

Dites ce que vous voulez, mais ce foo.Bar.Baz = quux.Answers[42]sera toujours beaucoup plus facile à lire que foo.getBar().setBaz(quux.getAnswers().getItem(42)). Et quand vous lisez des milliers de lignes de ceci par jour, cela fait une différence.

(Et si votre réponse naturelle au paragraphe ci-dessus est de dire: "Bien sûr, c'est difficile à lire, mais ce serait plus facile si vous le divisez en plusieurs lignes", alors je suis désolé de dire que vous avez complètement manqué le point .)

Aaronaught
la source
11

Je ne vois aucune raison pour laquelle vous ne devriez pas utiliser Propriétés en général.

Les propriétés automatiques en C # 3+ ne simplifient qu'un peu la syntaxe (à la manière du sucre syntatique).

Konstantin Tarkus
la source
s'il vous plaît, lisez les pages 215-216 de ce livre. Je suis sûr que vous savez qui est Jeffrey Richter!
Quan Mai
J'ai lu (CLR via C #, 2e éd.), Je ne suis pas d'accord avec sa position et je ne vois pas de vraies raisons de ne pas utiliser les propriétés!
abatishchev
C'est un bon livre, mais je ne suis pas d'accord avec l'auteur en ce moment.
Konstantin Tarkus
Où est exactement cet endroit où l'auteur suggère de ne pas utiliser Propriétés? Je n'ai rien trouvé sur les pages 215-217
Konstantin Tarkus
J'ai ajouté les opinions de Jeffrey dans ma question :). Vous pouvez le trouver aux pages 215-216 en édition imprimée :)
Quan Mai
9

C'est juste l'opinion d'une personne. J'ai lu pas mal de livres c # et je n'ai encore vu personne d'autre dire "ne pas utiliser les propriétés".

Personnellement, je pense que les propriétés sont l'une des meilleures choses à propos de c #. Ils vous permettent d'exposer l'état via le mécanisme de votre choix. Vous pouvez instancier paresseusement la première fois que quelque chose est utilisé et vous pouvez faire la validation sur la définition d'une valeur, etc. Lors de leur utilisation et de leur écriture, je pense juste aux propriétés comme des setters et des getters qui ont une syntaxe beaucoup plus agréable.

En ce qui concerne les mises en garde concernant les propriétés, il y en a quelques-unes. L'une est probablement une mauvaise utilisation des propriétés, l'autre peut être subtile.

Premièrement, les propriétés sont des types de méthodes. Il peut être surprenant de placer une logique compliquée dans une propriété, car la plupart des utilisateurs d'une classe s'attendront à ce que la propriété soit assez légère.

Par exemple

public class WorkerUsingMethod
{
   // Explicitly obvious that calculation is being done here
   public int CalculateResult()
   { 
      return ExpensiveLongRunningCalculation();
   }
}

public class WorkerUsingProperty
{
   // Not at all obvious.  Looks like it may just be returning a cached result.
   public int Result
   {
       get { return ExpensiveLongRunningCalculation(); }
   }
}

Je trouve que l'utilisation de méthodes pour ces cas aide à faire une distinction.

Deuxièmement, et plus important encore, les propriétés peuvent avoir des effets secondaires si vous les évaluez lors du débogage.

Disons que vous avez une propriété comme celle-ci:

public int Result 
{ 
   get 
   { 
       m_numberQueries++; 
       return m_result; 
   } 
}

Supposons maintenant que vous ayez une exception qui se produit lorsque trop de requêtes sont effectuées. Devinez ce qui se passe lorsque vous démarrez le débogage et survolez la propriété dans le débogueur? Mauvaises choses. Évitez de faire ça! L'examen de la propriété modifie l'état du programme.

Ce sont les seules mises en garde que j'ai. Je pense que les avantages des propriétés l'emportent largement sur les problèmes.

Mark Simpson
la source
6

Cette raison a dû être donnée dans un contexte très spécifique. C'est généralement l'inverse - il est recommandé d'utiliser les propriétés car elles vous donnent un niveau d'abstraction vous permettant de changer le comportement d'une classe sans affecter ses clients ...

Rashack
la source
+1 pour souligner implicitement l'importance du «contrat» entre le client et la propriété de la classe.
TheBlastOne
6

Je ne peux m'empêcher de choisir les détails des opinions de Jeffrey Richter:

Une propriété peut être en lecture seule ou en écriture seule; l'accès aux champs est toujours lisible et inscriptible.

Mauvais: les champs peuvent être marqués en lecture seule afin que seul le constructeur de l'objet puisse y écrire.

Une méthode de propriété peut lever une exception; l'accès aux champs ne lève jamais d'exception.

Erreur: l'implémentation d'une classe peut changer le modificateur d'accès d'un champ de public à privé. Les tentatives de lecture des champs privés lors de l'exécution entraîneront toujours une exception.

Cecil a un nom
la source
5

Je ne suis pas d'accord avec Jeffrey Richter, mais je peux deviner pourquoi il n'aime pas les propriétés (je n'ai pas lu son livre).

Même si les propriétés sont comme des méthodes (en termes d'implémentation), en tant qu'utilisateur d'une classe, je m'attends à ce que ses propriétés se comportent "plus ou moins" comme un champ public, par exemple:

  • il n'y a pas d'opération chronophage dans le getter / setter de propriété
  • le getter de propriété n'a aucun effet secondaire (l'appeler plusieurs fois, ne change pas le résultat)

Malheureusement, j'ai vu des propriétés qui ne se comportaient pas de cette façon. Mais le problème ne sont pas les propriétés elles-mêmes, mais les personnes qui les ont mises en œuvre. Donc, cela nécessite juste une certaine éducation.

M4N
la source
1
+1 car cela souligne l'importance d'un contrat propre. Avoir une propriété apparemment en lecture seule qui renvoie régulièrement une valeur différente sur chaque référence est une propriété readwrite - elle n'écrit tout simplement pas sur sa propre valeur, mais sur d'autres variables d'instance (directement ou indirectement). Ce n'est pas un mauvais style, mais doit être documenté (ou faire partie implicitement du contrat).
TheBlastOne
4

Il y a un moment où j'envisage de ne pas utiliser de propriétés, et c'est en écrivant du code .Net Compact Framework. Le compilateur CF JIT n'effectue pas la même optimisation que le compilateur JIT de bureau et n'optimise pas les accesseurs de propriété simples, donc dans ce cas, l'ajout d'une propriété simple provoque une petite quantité de code gonfler en utilisant un champ public. Habituellement, ce ne serait pas un problème, mais presque toujours dans le monde du Compact Framework, vous êtes confronté à des contraintes de mémoire strictes, donc même de minuscules économies comme celle-ci comptent.

Steve
la source
4

Vous ne devez pas éviter de les utiliser, mais vous devez les utiliser avec réserve et soin, pour les raisons données par d'autres contributeurs.

J'ai vu une fois une propriété appelée quelque chose comme Clients qui a ouvert en interne un appel hors processus à une base de données et lu la liste des clients. Le code client avait un 'for (int i to Customers.Count)' qui provoquait un appel séparé à la base de données à chaque itération et pour l'accès du client sélectionné. C'est un exemple flagrant qui démontre le principe de garder la propriété très légère - rarement plus qu'un accès au champ interne.

Un argument pour l'utilisation des propriétés est qu'elles vous permettent de valider la valeur définie. Une autre est que la valeur de de la propriété peut être une valeur dérivée, pas un seul champ, comme TotalValue = montant * quantité.

Rob Kent
la source
3

Personnellement, je n'utilise les propriétés que lors de la création de méthodes simples get / set. Je m'en éloigne pour arriver à des structures de données compliquées.

Steve
la source
3

L'argument suppose que les propriétés sont mauvaises car elles ressemblent à des champs, mais peuvent faire des actions surprenantes. Cette hypothèse est invalidée par les attentes des programmeurs .NET:

Les propriétés ne ressemblent pas à des champs. Les champs ressemblent à des propriétés.

• Une méthode de propriété peut lever une exception; l'accès aux champs ne lève jamais d'exception.

Ainsi, un champ est comme une propriété qui est garantie de ne jamais lever d'exception.

• Une propriété ne peut pas être transmise en tant que paramètre out ou ref à une méthode; un champ peut.

Ainsi, un champ est comme une propriété, mais il a des capacités supplémentaires: passer à une méthode ref/ outaccepting.

• Une méthode de propriété peut prendre un certain temps à s'exécuter; l'accès au champ se termine toujours immédiatement. [...]

Ainsi, un champ est comme une propriété rapide.

• Si elle est appelée plusieurs fois de suite, une méthode de propriété peut renvoyer une valeur différente à chaque fois; un champ renvoie la même valeur à chaque fois. La classe System.DateTime a une propriété en lecture seule Now qui renvoie la date et l'heure actuelles.

Ainsi, un champ est comme une propriété qui est garantie de renvoyer la même valeur à moins que le champ n'ait été défini sur une valeur différente.

• Une méthode de propriété peut provoquer des effets secondaires observables; l'accès sur le terrain ne le fait jamais.

Encore une fois, un champ est une propriété qui est garantie de ne pas faire cela.

• Une méthode de propriété peut nécessiter de la mémoire supplémentaire ou renvoyer une référence à quelque chose qui ne fait pas réellement partie de l'état de l'objet, donc la modification de l'objet retourné n'a aucun effet sur l'objet d'origine; l'interrogation d'un champ renvoie toujours une référence à un objet dont il est garanti qu'il fait partie de l'état de l'objet d'origine. Travailler avec une propriété qui renvoie une copie peut être très déroutant pour les développeurs, et cette caractéristique n'est souvent pas documentée.

Celui-ci peut être surprenant, mais pas parce que c'est une propriété qui fait cela. C'est plutôt que presque personne ne retourne des copies mutables dans les propriétés, de sorte que le cas de 0,1% est surprenant.

milleniumbug
la source
0

L'appel de méthodes au lieu de propriétés réduit considérablement la lisibilité du code d'appel. En J #, par exemple, utiliser ADO.NET était un cauchemar car Java ne prend pas en charge les propriétés et les indexeurs (qui sont essentiellement des propriétés avec des arguments). Le code résultant était extrêmement laid, avec des appels de méthode entre parenthèses vides partout.

La prise en charge des propriétés et des indexeurs est l'un des avantages de base de C # par rapport à Java.

Marty Solomon
la source