32 votes

Pourquoi les propriétés ne peuvent-elles pas être en lecture seule?

Cette question a été posée dans les commentaires de cette réponse. L'incapacité d'avoir des propriétés en lecture seule a été proposée comme une raison potentielle d'utiliser des champs au lieu de propriétés.

Par exemple:

class Rectangle
{
   private readonly int _width;
   private readonly int _height;

   public Rectangle(int width, int height)
   {
      _width = width;
      _height = height;
   }

   public int Width { get { return _width; } }
   public int Height { get { return _height; } }
}

Mais pourquoi ne pas simplement faire ceci?

public int Width { get; readonly set; }

Édition (clarification): Vous pouvez obtenir cette fonctionnalité dans le premier exemple. Mais pourquoi ne pouvez-vous pas utiliser la forme abrégée de propriété avec implémentation automatique pour faire la même chose? Ce serait également moins désordonné, car vous n'auriez pas à accéder directement aux champs dans votre constructeur; tout accès se ferait à travers la propriété.

Édition (mise à jour): À partir de C# 6.0, les propriétés en lecture seule sont supportées! object MyProp { get; } Cette propriété peut être définie en ligne (object MyProp { get; } = ...) ou dans le constructeur, mais nulle part ailleurs (tout comme les champs readonly).

7 votes

Une meilleure syntaxe serait public int Width { get; readonly set; }.

0 votes

@Jason : Cela semble effectivement mieux - Je l'ai modifié selon votre version.

3 votes

@Jason: Je ne sais pas, quelque chose à propos du concept d'un "setter en lecture seule" me semble très bizarre. C'est facile à comprendre ici, dans le contexte de cette question, mais je pense que si je le voyais sans prévenir, ça serait un moment de WTF.

24voto

itowlson Points 44174

Parce que le langage ne le permet pas.

Cela peut sembler être une réponse futile : après tout, les concepteurs du langage pourraient avoir déclaré que si vous utilisiez readonly sur une propriété automatique, cela signifierait "la propriété est modifiable mais uniquement dans le constructeur".

Mais les fonctionnalités ne viennent pas gratuitement. (Eric Gunnerson l'exprime comme "Chaque fonctionnalité commence avec moins 100 points."). Pour implémenter des propriétés automatiques en lecture seule aurait nécessité des efforts supplémentaires du compilateur pour prendre en charge le modificateur readonly sur une propriété (il s'applique actuellement uniquement aux champs), pour générer le champ de sauvegarde approprié et pour transformer les sets de la propriété en affectations au champ de sauvegarde. C'est un travail assez important pour prendre en charge quelque chose que l'utilisateur pourrait faire assez facilement en déclarant un champ de sauvegarde en lecture seule et en écrivant un getter de propriété en une ligne, et ce travail aurait un coût en termes de non-implémentation d'autres fonctionnalités.

Donc, très sérieusement, la réponse est que soit les concepteurs et implémentateurs du langage n'ont jamais pensé à l'idée, soit -- plus probablement -- ils ont pensé que ce serait bien d'avoir, mais ont décidé qu'il valait mieux dépenser leurs ressources limitées ailleurs. Il n'y a aucune contrainte technique qui empêche les concepteurs et implémentateurs du langage de fournir la fonctionnalité que vous suggérez : les raisons sont plus liées à l'économie du développement logiciel.

1 votes

C'est Eric Gunnerson qui dit que: blogs.msdn.com/ericgu/archive/2004/01/12/57985.aspx. Sinon, excellent article et la réponse correcte.

6 votes

C'était ce dernier. Cela est sur la liste depuis C# 3. Nous aimerions le faire, mais cela n'a jamais été une priorité suffisamment élevée. Nous avons littéralement des centaines d'idées pour de nouvelles fonctionnalités de langage et nous n'en faisons qu'une poignée dans chaque version.

0 votes

@EricLippert Puis-je vous demander s'il y a une chance que ce soit pris en charge à l'avenir?

17voto

Ben McCormack Points 10669

Si vous souhaitez rendre une propriété "en lecture seule" en termes de fonctionnalités, vous le faites en fournissant uniquement la méthode get, comme vous l'avez indiqué dans votre publication.

public int Width { get { return _width; } } 
public int Height { get { return _height; } } 

Le compilateur les considérera même comme "en lecture seule" si vous essayez d'écrire dedans.

Avoir un terme supplémentaire de readonly pour une propriété entrerait en conflit avec la fourniture de la méthode set. Cela me semble être une syntaxe pauvre, c'est-à-dire comment la personne qui le lit (ou le compilateur, d'ailleurs) sait ce qui prévaut : readonly ou set?

De plus, comme l'a expliqué la réponse à laquelle vous avez fait référence, readonly s'applique uniquement aux champs et limite l'écriture de ces champs à l'instanciation de la classe. Avec les propriétés, vous ne pouvez pas écrire dedans (je ne pense pas) même dans le constructeur s'ils n'ont qu'une méthode get.

2 votes

Vous avez raison, cela fournit la même fonctionnalité. C'est pourquoi cela a été inclus comme exemple. Ma question est : pourquoi ne pouvez-vous pas utiliser le raccourci de propriété à implémentation automatique pour faire la même chose ? Ce serait également moins confus, car vous n'auriez pas à accéder directement aux champs dans votre constructeur ; tout accès se ferait via la propriété.

1 votes

@Matthew bien sûr, peut-être que l'équipe responsable du compilateur C# aurait pu emprunter cette voie, mais ne serait-ce pas plus confus ? Comme l'a expliqué @Nate, vous pouvez avoir une propriété qui est readonly, mais pas automatique, ce qui a du sens. Bien qu'il soit possible d'atteindre ce dont vous parlez, j'imagine que cela serait confus (je serais confus, personnellement).

9voto

Crippledsmurf Points 2796

Vous pouvez rendre une propriété automatique en lecture seule en spécifiant le modificateur d'accès private pour le set comme ceci

public bool Property {get; private set;}

Le setter est toujours défini mais n'est plus visible à l'extérieur de la classe où la propriété est définie. En passant, il est parfois utile de définir le setter comme internal afin que les propriétés puissent être facilement définies à partir de la même assembly, mais pas par des appelants externes.

0 votes

Cela est vrai, cependant, une propriété sans setter ou avec un setter privé va quand même générer une erreur de compilation et empêcher la modification de la valeur, donc à moins que quelque chose m'échappe, l'option readonly et l'absence de setter sont équivalentes sur le plan fonctionnel

2 votes

Cela n'empêchera pas la modification de la valeur à l'intérieur de la classe depuis l'extérieur du constructeur.

1 votes

@Crippledsmurf: Vous avez raison que c'est une définition typique de "read-only", mais readonly en C# est un peu plus spécifique que cela. Cela implique qu'un champ ne peut être défini qu'une seule fois, et uniquement dans le constructeur (ou par initialisation en ligne).

2voto

Nate Points 9879

Les propriétés peuvent être en lecture seule, sauf les propriétés automatiques.

Les mots-clés get et set sont tous les deux requis pour les propriétés automatiques, et il n'a pas de sens pour une propriété en lecture seule d'avoir un set.

Vous pouvez définir une propriété régulière comme une propriété en lecture seule en définissant simplement le mot-clé get - cependant, même si l'exigence des mots-clés get et set pour les propriétés automatiques n'existait pas - la propriété en lecture seule ne pourrait pas être définie automatiquement car vous devez connaître le champ de sauvegarde pour pouvoir définir sa valeur internement (c'est-à-dire à travers le constructeur).

Je suppose qu'il pourrait y avoir un modèle/macro ou quelque chose défini dans VS pour générer du code de cette manière, mais cela ne pourrait pas faire partie du langage en lui-même.

0 votes

Il serait parfaitement logique pour un compilateur de permettre la syntaxe d'initialisation de champ avec une auto-propriété en lecture seule, du moins pour les champs qui n'implémentent pas IDisposable.

1voto

tvanfosson Points 268301

Je pense fondamentalement que le problème est que les propriétés ne sont rien de plus qu'un sucre syntaxique pour un champ avec des méthodes getter/setter optionnelles. Les propriétés automatiques génèrent le champ de sauvegarde donc elles nécessitent le "setter" sinon il n'y aurait aucun moyen de définir la valeur du champ de sauvegarde. Puisque les propriétés correspondent vraiment à des méthodes, pas à des champs, il n'a aucun sens de les rendre en lecture seule.

Même si cela était autorisé, lecture seule ne pourrait s'appliquer qu'aux propriétés automatiques. Pour les propriétés traditionnelles, vous pouvez mettre du code arbitraire à la fois dans le getter et le setter. Même si le setter était capable d'être invoqué uniquement dans le constructeur de la classe, le getter pourrait toujours muter la valeur en fonction de la logique que vous avez décidé d'y mettre. Cela serait totalement incompatible avec le concept de lecture seule, rendant ainsi nécessaire des règles de syntaxe différentes et un support pour les propriétés automatiques/traditionnelles. Puisqu'il y a un mécanisme -- en utilisant des propriétés traditionnelles avec seulement un getter défini ET un champ de sauvegarde en lecture seule comme dans la question référencée -- je ne vois aucun intérêt à modifier la syntaxe des propriétés et potentiellement introduire de la confusion pour quelque chose qui peut être réalisé assez facilement en utilisant les constructions linguistiques actuelles.

0 votes

Très bon point - "Puisque les propriétés se mappent vraiment sur des méthodes, pas sur des champs, il n'a aucun sens de les rendre en lecture seule."

2 votes

@tvanfosson, @Ben McCormack: C'est absolument faux. Qu'est-ce qui ne va pas avec public int Width { get; readonly set; } être mappé à readonly int _width; public int Width { get { return _width; } } et Width = 17 étant légal uniquement dans le constructeur?

0 votes

@Jason peut-être que je rate quelque chose, mais je ne comprends pas ce que vous dites. Je ne crois pas qu'il (ou moi) dise que vous ne devriez pas définir des propriétés qui manquent d'une méthode set (les rendant ainsi "en lecture seule" lors de la compilation). Il dit que le mot clé readonly ne peut être appliqué qu'aux champs, pas aux méthodes (et donc aux propriétés par extension).

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