Pourquoi il n'est pas recommandé d'avoir une propriété set-only?

9

Aujourd'hui, au travail, un de mes collègues a examiné mon code et m'a suggéré de supprimer une propriété de type ensemble et d'utiliser une méthode à la place.

Comme nous étions tous les deux occupés à autre chose, il m'a dit de regarder la Property Designsection du livre "Framework Design Guidelines". Dans le livre, l'écrivain vient de dire d'éviter:

Propriétés avec le setter ayant une accessibilité plus large que le getter

Et maintenant je me demande pourquoi il n'est pas recommandé d'avoir une propriété set-only? Quelqu'un peut-il clarifier pour moi?

Prashant Cholachagudda
la source
6
Pouvez-vous décrire la situation dans laquelle vous pensiez qu'une propriété en set-only était appropriée? Cela pourrait rendre les réponses un peu plus pertinentes.
JohnFx
1
J'essaie de penser à un exemple qui a un sens sémantique. La seule chose qui me vient à l'esprit est une Passwordpropriété sur une Userclasse. Vous pouvez le définir, mais vous ne pouvez pas l'obtenir. Vous pourriez alors avoir une HashedPasswordpropriété en lecture seule . Appeler l'ensemble ferait du hachage et changerait la HashedPasswordpropriété. Je ne vous crierais pas si vous faisiez ça.
Scott Whitlock

Réponses:

15

Je pense que cela peut avoir à voir avec les attentes. Les propriétés de jeu uniquement sont rares et les propriétés sont généralement utilisées pour les jeux "stupides" juste pour stocker une valeur sans trop de traitement. Si vous faites beaucoup de travail dans un setter, il est préférable d'utiliser une méthode - les gens s'attendent à ce que les méthodes prennent potentiellement beaucoup de temps à exécuter et aient potentiellement des effets secondaires. L'implémentation d'un type de comportement similaire dans une propriété peut entraîner un code qui viole les attentes.

Voici une section pertinente des directives d'utilisation des propriétés de Microsoft :

Propriétés vs méthodes

Les concepteurs de bibliothèques de classes doivent souvent décider entre l'implémentation d'un membre de classe en tant que propriété ou méthode. En général, les méthodes représentent des actions et les propriétés représentent des données. Utilisez les instructions suivantes pour vous aider à choisir entre ces options.

  • Utilisez une propriété lorsque le membre est un membre de données logique. Dans les déclarations de membres suivantes, Nameest une propriété car il s'agit d'un membre logique de la classe.
public string Name
{
    get 
    {
        return name;
    }
    set 
    {
        name = value;
    }
}

Utilisez une méthode lorsque:

  • L'opération est une conversion, telle que Object.ToString.
  • L'opération est suffisamment coûteuse pour que vous souhaitiez communiquer à l'utilisateur qu'il devrait envisager de mettre en cache le résultat.
  • L'obtention d'une valeur de propriété à l'aide de l' getaccesseur aurait un effet secondaire observable.
  • Appeler le membre deux fois de suite produit des résultats différents.
  • L'ordre d'exécution est important. Notez que les propriétés d'un type doivent pouvoir être définies et récupérées dans n'importe quel ordre.
  • Le membre est statique mais renvoie une valeur qui peut être modifiée.
  • Le membre renvoie un tableau. Les propriétés qui renvoient des tableaux peuvent être très trompeuses. Il est généralement nécessaire de renvoyer une copie de la matrice interne afin que l'utilisateur ne puisse pas modifier l'état interne. Ceci, associé au fait qu'un utilisateur peut facilement supposer qu'il s'agit d'une propriété indexée, conduit à un code inefficace. Dans l'exemple de code suivant, chaque appel à la propriété Methods crée une copie du tableau. Par conséquent, 2 ^ n + 1 copies du tableau seront créées dans la boucle suivante.
Type type = // Get a type.
for (int i = 0; i < type.Methods.Length; i++)
{
   if (type.Methods[i].Name.Equals ("text"))
   {
      // Perform some operation.
   }
}

[... sauté un exemple plus long ...]

Propriétés en lecture seule et en écriture seule

Vous devez utiliser une propriété en lecture seule lorsque l'utilisateur ne peut pas modifier le membre de données logique de la propriété. N'utilisez pas de propriétés en écriture seule.

Adam Lear
la source
Oui - le principe de la moindre surprise opère ici.
Paul Butcher
6

Parce que cela n'a tout simplement aucun sens dans la plupart des cas. Quelle propriété pourriez-vous avoir que vous pouvez définir mais pas lire?

Si OO est censé mieux représenter le monde réel, une propriété set only est susceptible de suggérer que votre modélisation est assez décalée.

Modifier : Voir également: /programming/4564928/are-set-only-properties-bad-practice qui dit essentiellement que ce n'est pas intuitif et qu'une propriété set only est fondamentalement une méthode sous un autre nom, vous devez donc utiliser un méthode.

Jon Hopkins
la source
1
J'ai déjà utilisé des propriétés set-only. Ils écrivent dans un champ privé de l'objet pour configurer son comportement. Ils sont utiles lorsque le code externe n'a pas besoin de connaître la valeur actuelle, mais peut avoir besoin de la changer. C'est rare, bien sûr, mais je l'ai vu se produire.
Mason Wheeler
@Mason - Je n'irais certainement pas jusqu'à dire que vous ne devriez jamais les utiliser, mais ils devraient essentiellement être l'exception plutôt que la règle.
Jon Hopkins
@MasonWheeler n'est-ce pas approximativement Foo Foo { private get; set; }? Je n'appellerais pas ça écrire seulement
Caleth
6

Eh bien, j'imagine que si vous pouvez définir une propriété sur quelque chose sans l'obtenir, vous ne saurez jamais si quelque chose d'autre change / écrase la valeur que vous définissez. Cela peut être un problème si vous comptez sur la valeur que vous définissez et que vous ne pouvez pas (pour une raison quelconque) la conserver jusqu'au moment où vous souhaitez l'obtenir.

L'utilisation d'une méthode au lieu d'une propriété set-only sera légèrement moins déroutante pour un utilisateur. Le nom de la méthode indique généralement set- ou get- , mais les noms de propriété n'indiquent généralement pas que quelque chose ne peut être défini et ne peut être obtenu. Je suppose que si la propriété était quelque chose comme "ReadOnlyBackgroundColour", cela ne serait pas déroutant pour les autres codeurs, mais cela aurait juste l'air bizarre.

FrustratedWithFormsDesigner
la source
Je suis d'accord, mais en quoi une méthode de définition serait-elle différente dans ce cas?
Travis Christian
1
@Travis Christian: Il semble que OP travaille avec une situation où il y a un setter mais pas de getter. Ils peuvent donc définir quelque chose, mais ils ne sauront jamais si cela change plus tard.
FrustratedWithFormsDesigner
@Frustrated Mais ils ne sauraient jamais non plus si quelque chose a été changé à nouveau avec une méthode.
Adam Lear
@Anna Lear ♦: S'il y a un getter, vous pouvez au moins tester la valeur avant de l'utiliser si vous avez un point dans votre code où la valeur que vous aviez définie peut soudainement être mise en doute.
FrustratedWithFormsDesigner
3
@Frustré, je suis d'accord. C'est juste que la question était d'utiliser une propriété set-only vs d'utiliser une méthode pour faire la même chose.
Adam Lear
-1

C'est un sujet très ancien mais qui m'a sauté aux yeux à ce stade tardif et j'aimerais avoir quelques commentaires alors que j'essaie de défendre les propriétés en écriture seule ...

J'ai un ensemble de ActiveReportclasses qui font partie d'un site Web qui sont instanciées et exécutées sur postback après un certain nombre de sélections d'utilisateurs.

Le code VB ressemble à ceci:

  Public Class SomeReport
    Private greader As New GenericReporting.CommonReader("AStoredProcedure", 
                                      {New SqlParameter("budget_id", 0)})

    Public WriteOnly Property BudgetID As Integer
      Set(value As Integer)
        greader.Parameters("budget_id").Value = value
      End Set
    End Property

    Public Sub New(Optional budget_id As Integer = 0)
      ' This call is required by the designer.
      InitializeComponent()

      ' Add any initialization after the InitializeComponent() call.
      BudgetID = budget_id
    End Sub
  End Class

Ces rapports utilisent des tripes génériques, CommonReaderprennent une procédure stockée et un tableau de SqlParameters par défaut , chacun ayant une propriété WriteOnly associée qui, selon la conception du rapport, peut être transmise en tant que paramètre lors de l'instanciation ou définie par l'utilisateur après l'instanciation avant appel de la Runméthode des rapports .

  '''''''''''''''''''''''
  ' Parameter taken from a user selected row of a GridView
  '
  Dim SomeBudgetID As Integer = gvBudgets.SelectedDataKey.Values(budget_id)

  '''''''''''''''''''''''      
  ' On Instantiation
  '
  Dim R as ActiveReport = New SomeReport(SomeBudgetID)
  R.Run()

  '''''''''''''''''''''''      
  ' Or On Instantiation using "With" syntax
  '
  Dim R as ActiveReport = New SomeReport() With {.BudgetID = SomeBudgetID}
  R.Run()

  '''''''''''''''''''''''
  ' Or After
  '
  Dim R as ActiveReport = New SomeReport()
  R.BudgetID = SomeBudgetID
  R.Run()

Donc, comme je le vois, avoir une propriété en écriture seule dans ce cas

  1. Permet une vérification de type plus forte car les SqlParameters sont un peu génériques
  2. Plus de flexibilité dans la création du rapport, le rapport peut être instancié immédiatement si tous les paramètres sont disponibles ou ajoutés par la suite au fur et à mesure qu'ils deviennent disponibles.
  3. Les propriétés prennent en charge la syntaxe "With" lors de l'instanciation
  4. Un "getter" est-il vraiment nécessaire car les paramètres sont connus de l'utilisateur et ne sont pas modifiés par le rapport?
  5. Étant donné que les SqlParameters sont des classes et non des valeurs primitives, les propriétés WriteOnly permettent une interface plus simple pour définir les paramètres

Voilà mes pensées.

Puis-je le convertir en méthode à la place? certes mais l'interface semble ... moins sympa

  R2.BudgetID = SomeBudgetID

contre

  R2.SetBudgetID(SomeBudgetID)
fnostro
la source