102 votes

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

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

A 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 en lecture et en écriture. Si vous définissez une propriété, il est préférable de proposer des méthodes d'accès get et set.

- Une méthode de propriété peut déclencher une exception ; l'accès à un champ ne déclenche jamais d'exception.

- Une propriété ne peut pas être transmise comme paramètre out ou ref à une méthode ; un champ peut l'être. Pour 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);
   }
}

- L'exécution d'une méthode de propriété peut prendre beaucoup de temps ; l'accès aux champs se termine toujours immédiatement. Une raison courante d'utiliser les propriétés est d'effectuer une synchronisation de fil, qui peut arrêter définitivement le thread. Par conséquent, une propriété ne doit pas être utilisée si la synchronisation du thread est nécessaire. Dans cette situation, il est préférable d'utiliser une méthode. De plus, si votre classe peut être 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érable à une propriété. A mon avis, les classes dérivées de MarshalByRefObject ne devraient jamais utiliser de propriétés.

- Si elle est appelée plusieurs fois dans une rangée, une méthode de propriété peut renvoyer une valeur différente à chaque fois. valeur différente à chaque fois ; un champ renvoie la même valeur à chaque fois. La classe System.DateTime possède une propriété Now en lecture seule. Now qui renvoie la date et l'heure actuelles. Chaque fois que vous interrogez cette propriété cette propriété, elle renvoie une valeur différente. Il s'agit là d'une erreur, et Microsoft aurait souhaité pouvoir corriger la classe en faisant de Now une méthode plutôt qu'une propriété.

- Une méthode de propriété peut provoquer des effets secondaires observables ; l'accès aux champs ne le fait jamais. En d'autres termes En d'autres termes, l'utilisateur d'un type doit être en mesure de définir diverses propriétés définies par un type dans l'ordre de son choix sans que l'on remarque un comportement différent du type. dans l'ordre de son choix sans remarquer un comportement différent du 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 partie de l'état de l'objet. qui ne fait pas réellement partie de l'état de l'objet, de sorte que la modification de l'objet renvoyé n'a pas d'effet sur l'objet original. n'a aucun effet sur l'objet d'origine ; l'interrogation d'un champ renvoie toujours une référence à un objet dont l'appartenance à l'état de l'objet est garantie. qui est garanti comme faisant partie de l'état de l'objet original. Travailler avec une propriété qui qui renvoie une copie peut être très déroutant pour les développeurs, et cette caractéristique n'est souvent pas documentée. pas documentée.

172voto

Jon Skeet Points 692016

La raison pour laquelle Jeff n'aime pas les propriétés est qu'elles ressemblent à des champs. Les développeurs qui ne comprennent pas la différence les traiteront comme s'il s'agissait de champs, en supposant qu'elles seront peu coûteuses à 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 suis d'accord pour dire 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 en utilisant des méthodes. (En particulier, ayant vu du code Java avec plusieurs getters et setters appelés dans la même déclaration, je sais que le code C# équivalent serait beaucoup plus simple à lire. La loi de Déméter, c'est très bien en théorie, mais parfois foo.Name.Length est vraiment la bonne chose à utiliser...)

(Et non, les propriétés mises en œuvre automatiquement ne changent pas vraiment 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.

35voto

foljs Points 1234

Bien, prenons ses arguments un par un :

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

C'est un avantage pour les propriétés, puisque vous avez un contrôle plus fin de l'accès.

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

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

- Une propriété ne peut pas être transmise comme paramètre out ou ref à une méthode ; un champ le peut.

Juste.

- Une méthode de propriété peut prendre un temps pour s'exécuter ; l'accès aux champs 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 méthode de propriété peut retourner une différente à chaque fois ; un champ renvoie la même valeur à chaque fois.

C'est faux. Comment savez-vous que la valeur du champ n'a pas été modifiée (peut-être par un autre fil) ?

La classe System.DateTime possède une propriété propriété Now en lecture seule qui renvoie la la date et l'heure actuelles. Chaque fois que vous cette propriété, elle renvoie une valeur valeur différente. Il s'agit d'une erreur, et Microsoft souhaiterait pouvoir réparer la classe en faisant de Now une méthode au lieu d'une propriété.

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

- Une méthode de propriété peut causer effets secondaires observables ; l'accès aux champs ne le fait jamais. En d'autres termes, un utilisateur de d'un type doit pouvoir définir diverses propriétés définies par un type dans dans l'ordre qu'il souhaite sans remarquer un comportement différent dans le type.

Juste.

- Une méthode de propriété peut nécessiter mémoire supplémentaire ou renvoyer une référence à quelque chose qui n'est pas qui ne fait pas partie de l'état de l'objet, Ainsi, la modification de l'objet retourné n'a n'a aucun effet sur l'objet original ; l'interrogation d'un champ renvoie toujours une référence à un objet qui est garanti comme faisant partie de l'état l'état de l'objet original. Travailler avec une propriété 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 être formulées à l'égard des getters et setters de Java - et nous les avons utilisés pendant un certain temps sans rencontrer de tels problèmes en 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.

18voto

jalf Points 142628

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

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

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

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

C'est un argument similaire à celui qui explique pourquoi Linus déteste le C++. Votre code peut agir de manière surprenante pour le lecteur. Il déteste la surcharge des opérateurs : a + b ne signifie pas nécessairement une simple addition. Il peut s'agir d'une opération extrêmement compliquée, tout comme les propriétés C#. Elle peut avoir des effets secondaires. Il peut faire n'importe quoi.

Honnêtement, je pense que c'est un argument faible. Les deux langages sont pleins de choses comme ça. (Devrions-nous éviter la surcharge des opérateurs en C# également ? Après tout, le même argument peut y être utilisé)

Les propriétés permettent l'abstraction. Nous pouvons prétendre que quelque chose est un champ normal, et l'utiliser comme si c'en était un, sans avoir à se soucier de ce qui se passe en coulisses.

C'est généralement considéré comme une bonne chose, mais cela dépend évidemment de l'écriture d'abstractions significatives par le programmeur. Vos propriétés debe se comportent comme des champs. Ils ne doivent pas avoir d'effets secondaires, ils ne doivent pas effectuer d'opérations coûteuses ou dangereuses. Nous voulons être en mesure de pensez à eux comme des champs.

Cependant, j'ai une autre raison de ne pas les trouver parfaits. Elles ne peuvent pas être passées par référence à d'autres fonctions.

Les champs peuvent être transmis comme ref Les fonctions peuvent être transmises en tant que délégués, ce qui permet à une fonction appelée d'y accéder directement. Les fonctions peuvent être transmises en tant que délégués, ce qui permet à 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 devraient pas être utilisées. Pour de nombreux usages, elles sont excellentes.

17voto

Aaronaught Points 73049

En 2009, ce conseil ressemblait à une simple fanfaronnade de la part de l'Union européenne. Qui a déplacé mon fromage variété. Aujourd'hui, elle est presque ridiculement obsolète.

Un point très important que de nombreuses réponses semblent contourner sans l'aborder de front est que ces prétendus "dangers" des propriétés sont les suivants une partie intentionnelle de la conception du cadre !

Oui, les propriétés le peuvent :

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

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

  • Il faut beaucoup de temps pour l'exécuter. La comparaison valable ici est avec méthodes qui prennent autant de temps - pas champs . L'affirmation selon laquelle "une méthode est préférable" ne repose sur aucune base autre que la préférence personnelle d'un auteur.

  • Renvoyer des valeurs différentes de son getter lors d'exécutions ultérieures. Cela ressemble presque à une plaisanterie à côté du point vantant les mérites de l'utilisation de la fonction ref / out des paramètres avec des champs, dont la valeur d'un champ après un ref / out est à peu près garanti d'être différent de sa valeur précédente, et ce de manière imprévisible.

    Si nous parlons du cas spécifique (et pratiquement académique) de l'accès à un seul fil sans couplages afférents, c'est assez bien compris que c'est une mauvaise conception des propriétés que d'avoir des effets secondaires qui changent d'état de manière visible, et peut-être que ma mémoire est défaillante, mais je n'arrive pas à me souvenir d'exemples de personnes utilisant DateTime.Now et s'attendre à ce que la même valeur ressorte à chaque fois. En tout cas, pas de cas où ils n'auraient pas tout aussi bien foiré avec une hypothétique DateTime.Now() .

  • provoquer 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 comme fonctionnalité du langage en premier lieu. La propre version de Microsoft Conception de la propriété indiquent que l'ordre du setter ne devrait pas avoir d'importance, car agir autrement impliquerait couplage temporel . Il est certain qu'il est impossible d'obtenir un couplage temporel avec les seuls champs, mais c'est uniquement parce qu'il est impossible de provoquer un comportement significatif avec les seuls champs, jusqu'à ce qu'une méthode soit exécutée.

    Les accesseurs de propriété peuvent en fait aider prévenir certains types de couplage temporel en forçant l'objet à se mettre dans un état valide avant toute action - par exemple, si une classe a un objet de type StartDate et un EndDate puis de régler le EndDate avant le StartDate pourrait forcer le StartDate de retour également. Cela est vrai même dans les environnements multithreads ou asynchrones, y compris l'exemple évident d'une interface utilisateur pilotée par événements.

Les propriétés peuvent faire d'autres choses que les champs ne peuvent pas faire :

  • Chargement paresseux l'un des moyens les plus efficaces de prévenir les erreurs d'ordre d'initialisation.
  • Notifications de changement qui constituent l'essentiel de la base de l'histoire de l'entreprise. MVVM l'architecture.
  • Héritage par exemple en définissant une abstraction Type o Name Ainsi, les classes dérivées peuvent 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 toute personne ayant eu à travailler avec COM interop et l'inévitable déversement de Item(i) les appels reconnaîtront comme une chose merveilleuse.
  • Travailler avec PropertyDescriptor ce qui est essentiel pour la création de designers et pour les cadres XAML en général.

Richter est manifestement un auteur prolifique qui en sait long 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 qu'il figure dans ses révisions plus récentes - j'espère sincèrement que non), il ne voulait tout simplement pas se défaire de ses vieilles habitudes et avait du mal à accepter les conventions du C# (par rapport au C++, par exemple).

Ce que je veux dire par là, c'est que son argument des "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 ne se comportent pas forcément comme des champs. Et le problème avec cette déclaration est, ce n'est pas vrai ou, au mieux, c'est très trompeur. Propriétés no ressemblent à des champs - du moins, ils ne le sont pas. supposée pour ressembler à des champs.

Il y a deux muy des conventions de codage 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 siempre être privé, jamais public.
  2. Les champs doivent être déclarés en camelCase. Les propriétés sont en PascalCase.

Ainsi, il n'y a aucune ambiguïté sur le fait que Foo.Bar = 42 est un accesseur de propriété ou un accesseur de champ. C'est un accesseur de propriété et il doit être traité comme toute autre méthode - il peut être lent, il peut lever une exception, etc. C'est la nature même de Abstraction - la réaction de la classe déclarante est entièrement laissée à sa discrétion. Les concepteurs de classes doivent appliquer le principe de la moindre surprise, mais les appelants ne doivent rien présumer d'une propriété, si ce n'est qu'elle fait ce qui est écrit sur la boîte. C'est fait exprès.

L'alternative aux propriétés, ce sont des méthodes getter/setter partout. C'est l'approche Java, et elle a été controversé depuis le début . C'est bien si c'est votre truc, mais ce n'est tout simplement pas notre façon de faire dans le camp .NET. Nous essayons, du moins dans les limites d'un système à typage statique, d'éviter ce que Fowler appelle Bruit syntaxique . Nous ne voulons pas de parenthèses supplémentaires, ni de get / set des verrues, ou des signatures de méthodes supplémentaires - pas si nous pouvons les éviter sans perte de clarté.

Dis ce que tu veux, mais 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 ce genre 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 divisiez en plusieurs lignes", alors je suis désolé de vous dire que vous avez <em>complètement </em>a raté le coche).

11voto

Konstantin Tarkus Points 16862

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

Les propriétés automatiques en C# 3+ ne font que simplifier un peu la syntaxe (à la manière du sucre syntaxique).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X