L'orientation générale pour C # est de toujours utiliser une propriété sur un domaine public. Cela a du sens: en exposant un champ, vous exposez beaucoup de détails d'implémentation. Avec une propriété, vous encapsulez ce détail afin qu'il soit caché de la consommation de code, et les changements d'implémentation sont découplés des changements d'interface.
Cependant, je me demande s'il existe parfois une exception valide à cette règle lors de l'utilisation du readonly
mot clé. En appliquant ce mot-clé à un domaine public, vous faites une garantie supplémentaire: l'immuabilité. Ce n'est pas seulement un détail d'implémentation, l'immuabilité est quelque chose qui pourrait intéresser un consommateur. L'utilisation d'un readonly
champ le fait partie du contrat public, et quelque chose qui ne peut pas être rompu par de futurs changements ou héritages sans avoir à modifier l'interface publique. C'est quelque chose qu'une propriété ne peut pas offrir.
La garantie de l'immuabilité est-elle donc une raison légitime de choisir un readonly
champ plutôt qu'une propriété dans certains cas?
(Pour plus de précision, je ne dis certainement pas que vous devriez toujours faire ce choix juste parce que le champ est immuable en ce moment, uniquement lorsqu'il a du sens dans le cadre de la conception de la classe et que son utilisation prévue inclut l'immuabilité dans son contrat. Je suis surtout intéressé par des réponses se concentrant sur la question de savoir si cela peut être justifié, plutôt que sur des cas spécifiques où ce n'est pas le cas, par exemple lorsque vous avez besoin que le membre soit sur un interface
ou que vous souhaitiez effectuer un chargement paresseux.)
la source
Réponses:
Les champs publics statiques en lecture seule sont certainement corrects. Ils sont recommandés dans certaines situations, comme lorsque vous voulez un objet constant nommé mais que vous ne pouvez pas utiliser le
const
mot - clé.Les champs membres en lecture seule sont un peu plus compliqués. Il n'y a pas beaucoup d'avantages sur une propriété sans setter public, et il y a un inconvénient majeur: les champs ne peuvent pas être membres d'interfaces. Donc, si vous décidez de refactoriser votre code pour qu'il fonctionne contre une interface au lieu d'un type concret, vous devrez changer vos champs en lecture seule en propriétés avec des getters publics.
Une propriété publique non virtuelle sans setter protégé offre une protection contre l'héritage, sauf si les classes héritées ont accès au champ de sauvegarde. Vous pouvez appliquer complètement ce contrat dans la classe de base.
Ne pas pouvoir changer "l'immuabilité" du membre sans changer l'interface publique de la classe n'est pas vraiment un obstacle dans ce cas. Habituellement, si vous souhaitez transformer un champ public en propriété, cela se passe bien, sauf qu'il y a deux cas à traiter:
object.Location.X = 4
n'est possible que s'ilLocation
s'agit d'un champ. Cela n'est cependant pas pertinent pour un champ en lecture seule, car vous ne pouvez pas modifier une structure en lecture seule. (Cela suppose queLocation
c'est un type de valeur - sinon, ce problème ne s'appliquerait pas de toute façon carreadonly
il ne protège pas contre ce genre de chose.)out
ouref
. Encore une fois, cela n'est pas vraiment pertinent pour un champ en lecture seule, car les paramètresout
etref
ont tendance à être modifiés, et c'est une erreur de compilation de toute façon de passer une valeur en lecture seule comme out ou ref.En d'autres termes, bien que la conversion d'un champ en lecture seule en une propriété en lecture seule rompt la compatibilité binaire, d'autres codes source n'auraient qu'à être recompilés sans aucune modification pour gérer cette modification. Cela rend la garantie vraiment facile à briser.
Je ne vois aucun avantage dans le
readonly
champ membre, et l'incapacité d'avoir ce genre de chose sur une interface est assez pour moi un inconvénient que je ne l'utiliserais pas.la source
D'après mon expérience, le
readonly
mot-clé n'est pas la magie qu'il promet.Par exemple, vous avez une classe où le constructeur était simple. Compte tenu de l'utilisation (et du fait que certaines propriétés / champs de classe sont immuables après la construction), vous pourriez penser que cela n'a pas d'importance, vous avez donc utilisé le
readonly
mot - clé.Plus tard, la classe devient plus complexe, tout comme son constructeur. (Supposons que cela se produise dans un projet expérimental ou dont la vitesse de zoom est suffisamment élevée hors de la portée / du contrôle, mais vous devez le faire fonctionner d'une manière ou d'une autre.) Vous constaterez que les champs qui ne
readonly
peuvent être modifiés qu'à l'intérieur du constructeur - vous ne peut pas le modifier dans les méthodes même si cette méthode n'est appelée qu'à partir d'un constructeur.Cette limitation technique a été reconnue par les concepteurs de C # et pourrait être corrigée dans une future version. Mais jusqu'à ce qu'il soit corrigé, l'utilisation de
readonly
est plus restrictive et pourrait encourager un mauvais style de codage (tout mettre dans la méthode constructeur).Pour rappel, ni la
readonly
propriété ni le non-public-setter ne garantissent un "objet entièrement initialisé". En d'autres termes, c'est le concepteur d'une classe qui décide ce que signifie "complètement initialisé" et comment le protéger contre une utilisation par inadvertance, et une telle protection n'est généralement pas infaillible, ce qui signifie que quelqu'un pourrait trouver un moyen de contourner ce problème.la source
readonly
champ en tant que paramètreout
ouref
à d'autres méthodes, qui seront ensuite libres de le modifier comme bon leur semble.Les champs sont TOUJOURS des détails d'implémentation. Vous ne voulez pas exposer les détails de votre implémentation.
Un principe fondamental du génie logiciel est que nous ne savons pas quelles seront les exigences à l'avenir. Bien que votre
readonly
domaine soit bon aujourd'hui, rien ne permet de penser qu'il fera partie des exigences de demain. Que se passe-t-il si demain il est nécessaire d'implémenter un compteur d'accès pour déterminer le nombre d'accès à ce champ? Que faire si vous devez autoriser des sous-classes à remplacer le champ?Les propriétés sont si faciles à utiliser et sont tellement plus flexibles que les champs publics que je ne peux pas penser à un cas d'utilisation unique où je choisirais à la fois c # comme langue et utiliserais des champs publics en lecture seule sur une classe. Si les performances étaient si serrées que je ne pouvais pas supporter l'appel de méthode supplémentaire, j'utiliserais probablement un langage différent.
Ce n'est pas parce que nous pouvons faire quelque chose avec la langue que nous devons faire quelque chose avec la langue.
En fait, je me demande si les concepteurs de langages regrettent que les champs soient rendus publics. Je ne me souviens pas de la dernière fois où j'ai même envisagé d'utiliser des champs publics non const dans mon code.
la source
Rational
avec public, immuableNumerator
etDenominator
membres, je pourrais être extrêmement confiant que ces membres n'auront pas besoin de chargement paresseux ou d'un compteur de hit ou similaire?float
types pour leNumerator
etDenominator
n'aura pas besoin d'être changée endoubles
?float
nidouble
. Ils devraient l'êtreint
,long
ouBigInteger
. Peut-être que ceux-ci doivent changer ... mais si c'est le cas, ils devraient également changer dans l'interface publique, donc vraiment l'utilisation des propriétés n'ajoute aucune encapsulation autour de ce détail.Non, ce n'est pas une justification.
Utiliser le readonly comme garantie d'inmutabilité et non comme une justification ressemble plus à un hack.
En lecture seule signifie que la valeur est affectée par un constructeur o lorsque la variable est définie.
Je pense que ce sera une mauvaise pratique
Si vous voulez vraiment garantir l'immuabilité, utilisez une interface qui a plus d'avantages que d'inconvénients.
Exemple d'interface simple:
la source