Les propriétés en écriture seule ont-elles des applications pratiques?

Je ne sais pas pourquoi j’ai commencé à y penser, mais maintenant je n’arrive pas à arrêter.

En C # – et probablement beaucoup d’autres langages, je me souviens que Delphi vous laissait faire cela aussi – il est légal d’écrire cette syntaxe:

class WeirdClass { private void Hello(ssortingng name) { Console.WriteLine("Hello, {0}!", name); } public ssortingng Name { set { Hello(name); } } } 

En d’autres termes, la propriété a un setter mais pas de getter , c’est en écriture seule .

Je suppose que je ne peux penser à aucune raison pour laquelle cela devrait être illégal , mais je ne l’ai jamais vraiment vu dans la nature, et j’ai semblé un code assez shiny / horrifiant dans la nature. Cela ressemble à une odeur de code; il semble que le compilateur devrait me donner un avertissement:

CS83417: La propriété “Nom” semble complètement inutile et stupide. Mauvais programmeur! Envisagez de remplacer par une méthode.

Mais peut-être n’ai-je pas fait cela assez longtemps ou travaillé dans un domaine trop étroit pour voir des exemples d’utilisation efficace d’un tel concept.

Existe-t-il des exemples réels de propriétés en écriture seule qui ne peuvent pas être remplacées par des appels de méthode simples ou deviennent moins intuitives?

Les propriétés en écriture sont en fait très utiles et je les utilise fréquemment. Tout est une question d’ encapsulation , limitant l’access aux composants d’un object. Vous devez souvent fournir un ou plusieurs composants à une classe qui doit être utilisée en interne, mais il n’y a aucune raison de les rendre accessibles aux autres classes. Cela rend simplement votre classe plus confuse (“est-ce que j’utilise ce getter ou cette méthode?”), Et plus probable que votre classe puisse être altérée ou que son véritable objective soit ignoré.

Voir “Pourquoi les méthodes getter et setter sont mauvaises” pour une discussion intéressante à ce sujet. Je ne suis pas aussi hardcore que l’auteur de l’article, mais je pense que c’est une bonne chose à penser. En général, j’utilise des seters, mais j’utilise rarement les getters.

Ma première réaction à cette question a été la suivante: “Qu’en est-il de la méthode java.util.Random # setSeed ?”

Je pense que les propriétés en écriture seule sont utiles dans plusieurs scénarios. Par exemple lorsque vous ne voulez pas exposer la représentation interne ( encapsulation ), tout en permettant de changer l’état de l’object. java.util.Random est un très bon exemple d’une telle conception.

Code Analysis (aka FxCop) vous donne un diagnostic:

CA1044 : Microsoft.Design: Étant donné que la propriété ‘WeirdClass.Name’ est en écriture seule, ajoutez un getter de propriété avec une accessibilité supérieure ou égale à son setter ou convertissez cette propriété en une méthode.

J’ai un code similaire au suivant dans un projet XNA. Comme vous pouvez le voir, Scale est en écriture seule, il est utile et (raisonnablement) intuitif et une propriété read ( get ) n’a pas de sens pour cela. Bien sûr, il pourrait être remplacé par une méthode, mais j’aime la syntaxe.

 public class MyGraphicalObject { public double ScaleX { get; set; } public double ScaleY { get; set; } public double ScaleZ { get; set; } public double Scale { set { ScaleX = ScaleY = ScaleZ = value; } } // more... } 

Faire quelque chose en écriture seule est utile quand vous n’êtes pas censé lire ce que vous écrivez.

Par exemple, lorsque vous dessinez des choses sur l’écran (c’est précisément ce que fait le gestionnaire de fenêtres de bureau sous Windows):
Vous pouvez certainement dessiner sur un écran, mais vous ne devriez jamais avoir besoin de relire les données (et encore moins espérer obtenir le même design qu’auparavant).

Maintenant, si les propriétés en écriture seule sont utiles (par opposition aux méthodes), je ne suis pas certain de la fréquence à laquelle elles sont utilisées. Je suppose que vous pouvez imaginer une situation avec une propriété “BackgroundColor”, où l’écriture définit la couleur d’arrière-plan de l’écran, mais la lecture n’a pas de sens (nécessairement).
Donc, je ne suis pas sûr de cette partie, mais en général, je voulais simplement souligner qu’il existe des cas d’utilisation pour des situations dans lesquelles vous écrivez uniquement des données et que vous ne les lisez jamais.

Une utilisation pour une propriété en écriture seule consiste à prendre en charge l’dependency injection de setter, généralement utilisée pour les parameters facultatifs.

Disons que j’ai eu un cours:

 public class WhizbangService { public WhizbangProvider Provider { set; private get; } } 

Le WhizbangProvider n’est pas destiné à être accédé par le monde extérieur. Je ne voudrais jamais interagir avec le service.Provider . service.Provider , c’est trop complexe. J’ai besoin d’une classe comme WhizbangService pour faire office de façade. Pourtant, avec le setter, je peux faire quelque chose comme ceci:

 service.Provider = new FireworksShow(); service.Start(); 

Et le service commence un feu d’artifice. Ou peut-être préférez-vous voir un spectacle d’eau et de lumière:

 service.Stop(); service.Provider = new FountainDisplay(new SsortingngOfLights(), 20, UnitOfTime.Seconds); service.Start(); 

Etc….

Cela devient particulièrement utile si la propriété est définie dans une classe de base. Si vous avez choisi l’injection de construction pour cette propriété, vous devez écrire une surcharge de constructeur dans toute classe dérivée.

 public abstract class DisplayService { public WhizbangProvider Provider { set; private get; } } public class WhizbangService : DisplayService { } 

Ici, l’alternative avec l’injection de constructeur est:

 public abstract class DisplayService { public WhizbangProvider Provider; protected DisplayService(WhizbangProvider provider) { Provider = provider ?? new DefaultProvider(); } } public class WhizbangService : DisplayService { public WhizbangService(WhizbangProvider provider) : base(provider) { } } 

À mon avis, cette approche est plus compliquée, car vous avez besoin de certaines opérations internes de la classe, en particulier si vous transmettez la valeur null au constructeur, vous obtiendrez une valeur par défaut raisonnable.

Bien que les directives de conception .NET recommandent d’utiliser une méthode (“SetMyWriteOnlyParameter”) au lieu d’une propriété en écriture seule, je trouve les propriétés en écriture seule utiles lors de la création d’objects liés à partir d’une représentation sérialisée (à partir d’une firebase database).

Notre application représente des systèmes de production de champs pétrolifères. Nous avons le système dans son ensemble (l’object “Model”) et divers objects Reservoir, Well, Node, Group etc.

Le modèle est créé et lu à partir de la firebase database en premier – les autres objects doivent savoir à quel modèle ils appartiennent. Cependant, le modèle doit savoir quel object inférieur représente le total des ventes. Il est logique que ces informations soient stockées dans une propriété Model. Si nous ne voulons pas avoir à faire deux lectures d’informations sur le modèle, nous devons pouvoir lire le nom de l’object Sales avant sa création. Ensuite, nous définissons la variable “SalesObject” pour qu’elle pointe vers l’object réel (de sorte que, par exemple, toute modification par l’utilisateur du nom de cet object ne pose pas de problème)

Nous préférons utiliser une propriété en écriture seule – ‘SalesObjectName = “TopNode”‘ – plutôt qu’une méthode – ‘SetSalesObjectName (“TopNode”) – car il nous semble que ce dernier suggère l’existence de SalesObject.

C’est un point mineur, mais suffisant pour nous donner envie d’utiliser une propriété en écriture seule.

Dans le modèle MVP, il est courant d’écrire une propriété avec un setter sur la vue (pas besoin d’un getter) – chaque fois que le présentateur le définit, la propriété utilise cette valeur pour mettre à jour un élément de l’interface utilisateur.

Voir ici pour une petite démonstration:

 public partial class ShowMeTheTime : Page, ICurrentTimeView { protected void Page_Load(object sender, EventArgs e) { CurrentTimePresenter presenter = new CurrentTimePresenter(this); presenter.InitView(); } public DateTime CurrentTime { set { lblCurrentTime.Text = value.ToSsortingng(); } } } 

La méthode InitViewer présente simplement la valeur de la propriété:

 public void InitView() { view.CurrentTime = DateTime.Now; } 

En ce qui me concerne, ils ne le font pas. Chaque fois que j’ai utilisé une propriété en écriture seule comme un hack rapide, je suis venu plus tard pour le regretter. Habituellement, je me retrouve avec un constructeur ou une propriété complète.

Bien sûr, j’essaie de prouver que c’est négatif, alors peut-être que quelque chose me manque.

Je ne peux pas arrêter de penser à ça non plus. J’ai un cas d’utilisation pour une propriété “en écriture seule”. Je ne peux pas voir le bon moyen d’en sortir.

Je veux construire un atsortingbut C # qui dérive de AuthorizeAtsortingbute pour une application ASP.NET MVC. J’ai un service (par exemple, IStore) qui renvoie des informations permettant de décider si l’utilisateur actuel doit être autorisé. L’injection du constructeur ne fonctionnera pas, car

 public AllowedAtsortingbute: AuthorizeAtsortingbute { public AllowedAtsortingbute(IStore store) {...} private IStore Store { get; set; } ... } 

make stocke un paramètre d’atsortingbut positionnel, mais IStore n’est pas un type de paramètre d’atsortingbut valide et le compilateur ne crée pas de code annoté avec lui. Je suis obligé de me rabattre sur Injection Setter Property.

 public AllowedAtsortingbute: AuthorizeAtsortingbute { [Inject] public IStore Store { private get; set; } ... } 

En plus de toutes les autres choses négatives à propos de Property Setter au lieu de Construct Injection, le service est une propriété en écriture seule. Assez mauvais pour que je doive exposer le setter aux clients qui ne devraient pas avoir besoin de connaître les détails de l’implémentation. Cela ne favoriserait personne de laisser les clients voir le getter, aussi.

Je pense que l’avantage de l’dependency injections l’emporte sur les directives par rapport aux propriétés en écriture seule pour ce scénario, sauf si quelque chose me manque.

Non, je peux imaginer n’importe quel cas où ils ne peuvent pas être remplacés, bien qu’il puisse y avoir des gens qui les considèrent plus lisibles.

Cas hypothétique:

 CommunicationDevice.Response = "Hello, World" 

au lieu de

 CommunicationDevice.SendResponse("Hello, World") 

La tâche principale serait d’effectuer des effets secondaires ou de validation des entrées-sorties.

Fait intéressant, VB .NET a même son propre mot-clé pour ce genre de propriété étrange;)

 Public WriteOnly Property Foo() As Integer Set(value As Integer) ' ... ' End Set End Property 

même si de nombreuses propriétés “en écriture seule” de l’extérieur ont un getter privé.

J’ai récemment travaillé sur une application qui traitait les mots de passe. (Notez que je ne prétends pas que ce qui suit est une bonne idée; je ne fais que décrire ce que j’ai fait.)

J’ai eu une classe, HashingPassword , qui contenait un mot de passe. Le constructeur a pris un mot de passe comme argument et l’a stocké dans un atsortingbut privé. Étant donné l’un de ces objects, vous pouvez soit acquérir un hachage salé pour le mot de passe, soit vérifier le mot de passe par rapport à un hachage salé donné. Il n’y avait bien sûr aucun moyen de récupérer le mot de passe d’un object HashingPassword .

Alors j’ai eu un autre object, je ne me souviens plus de ce que c’était; supposons que c’était une banane protégée par mot de passe. La classe Banana avait une propriété de jeu uniquement appelée Password , qui créait un HashingPassword partir de la valeur donnée et la stockait dans un atsortingbut privé de Banana . Comme l’atsortingbut de password de HashingPassword était privé, il n’existait aucun moyen d’écrire un getter pour cette propriété.

Alors, pourquoi ai-je eu une propriété de jeu uniquement appelée Password au lieu d’une méthode appelée SetPassword ? Parce que c’était logique. L’effet était en fait de définir le mot de passe de la Banana , et si je voulais définir le mot de passe d’un object Banana , je m’attendrais à le faire en définissant une propriété, pas en appelant une méthode.

L’utilisation d’une méthode appelée SetPassword n’aurait eu aucun inconvénient majeur. Mais je ne vois aucun avantage significatif non plus.

Je sais que cela existe depuis longtemps, mais je l’ai trouvé et j’ai un cas d’utilisation valide (à mon humble avis):

Lorsque vous enregistrez des parameters dans un appel webapi depuis ajax, vous pouvez simplement essayer de remplir les propriétés de la classe de parameters et inclure la validation ou autre chose.

 public int MyFancyWepapiMethod([FromBody]CallParams p) { return p.MyIntPropertyForAjax.HasValue ? p.MyIntPropertyForAjax.Value : 42; } public class CallParams { public int? MyIntPropertyForAjax; public object TryMyIntPropertyForAjax { set { try { MyIntPropertyForAjax = Convert.ToInt32(value); } catch { MyIntPropertyForAjax = null; } } } } 

Côté JavaScript, vous pouvez simplement remplir les parameters, y compris la validation:

 var callparameter = { TryMyIntPropertyForAjax = 23 } 

ce qui est sûr dans cet exemple, mais si vous gérez userinput, il peut ne pas être sûr que vous ayez une valeur valide ou quelque chose de similaire.

Eh bien, techniquement, il n’y a rien de mal avec une propriété Setter-only per-per. Le Setter pourrait faire une validation et peut-être que d’autres méthodes – publiques ou privées – pourraient en dépendre.

Par exemple:

 class SomeClass { private int _someVar; SomeClass(int someVar) { if(someVar > 0) _someVar = someVar; } public int SomeVar { set { if(value > 0) _someVar = value; } } public ssortingng SomeFunction(){ return "This is an important function that uses _someVar " + _someVar; } } 

La déclaration elle-même peut donc être légale et valide. Votre corps de méthode a cependant une énorme odeur de code, mais ce n’est pas le travail des compilateurs.