Perché non è consigliabile avere la proprietà solo set?


9

Oggi al lavoro uno dei miei colleghi ha esaminato il mio codice e mi ha suggerito di rimuovere una proprietà solo set e utilizzare invece un metodo.

Dato che entrambi eravamo impegnati con altre cose, mi ha detto di dare un'occhiata alla Property Designsezione dal libro "Framework Design Guidelines". Nel libro lo scrittore ha appena detto di evitare:

Proprietà con setter con accessibilità più ampia rispetto al getter

E ora mi chiedo perché non è consigliabile avere la proprietà set-only? Qualcuno può chiarire per me?


6
Puoi descrivere la situazione in cui pensavi che una proprietà solo set fosse appropriata? Potrebbe rendere le risposte un po 'più pertinenti.
JohnFx,

1
Sto cercando di pensare a un esempio che ha senso semanticamente. L'unica cosa che viene in mente è una Passwordproprietà di una Userclasse. Puoi impostarlo, ma non puoi ottenerlo. È quindi possibile avere una HashedPasswordproprietà di sola lettura . Chiamare il set farebbe l'hash e cambierebbe la HashedPasswordproprietà. Non ti urlarei se lo facessi.
Scott Whitlock,

Risposte:


15

Penso che potrebbe avere a che fare con le aspettative. Le proprietà di solo set non sono comuni e le proprietà vengono in genere utilizzate per set "stupidi" solo per memorizzare un valore senza molta elaborazione. Se stai lavorando molto in un setter, è meglio usare un metodo: le persone si aspettano che i metodi impieghino molto tempo a essere eseguiti e potenzialmente abbiano effetti collaterali. L'implementazione di un comportamento simile in una proprietà può comportare il codice che viola le aspettative.

Ecco una sezione pertinente delle Linee guida per l'uso delle proprietà di Microsoft :

Proprietà vs. metodi

I progettisti di librerie di classi spesso devono decidere tra l'implementazione di un membro di classe come proprietà o metodo. In generale, i metodi rappresentano azioni e le proprietà rappresentano i dati. Usa le seguenti linee guida per aiutarti a scegliere tra queste opzioni.

  • Utilizzare una proprietà quando il membro è un membro di dati logici. Nelle seguenti dichiarazioni dei membri, Nameè una proprietà perché è un membro logico della classe.
public string Name
{
    get 
    {
        return name;
    }
    set 
    {
        name = value;
    }
}

Utilizzare un metodo quando:

  • L'operazione è una conversione, ad esempio Object.ToString.
  • L'operazione è abbastanza costosa che si desidera comunicare all'utente che devono considerare la memorizzazione nella cache del risultato.
  • Ottenere un valore di proprietà usando l' getaccessor avrebbe un effetto collaterale osservabile.
  • Chiamare il membro due volte in successione produce risultati diversi.
  • L'ordine di esecuzione è importante. Si noti che le proprietà di un tipo dovrebbero poter essere impostate e recuperate in qualsiasi ordine.
  • Il membro è statico ma restituisce un valore che può essere modificato.
  • Il membro restituisce un array. Le proprietà che restituiscono array possono essere molto fuorvianti. Di solito è necessario restituire una copia dell'array interno in modo che l'utente non possa modificare lo stato interno. Questo, unito al fatto che un utente può facilmente supporre che sia una proprietà indicizzata, porta a un codice inefficiente. Nel seguente esempio di codice, ogni chiamata alla proprietà Methods crea una copia dell'array. Di conseguenza, nel ciclo seguente verranno create 2 ^ n + 1 copie dell'array.
Type type = // Get a type.
for (int i = 0; i < type.Methods.Length; i++)
{
   if (type.Methods[i].Name.Equals ("text"))
   {
      // Perform some operation.
   }
}

[... ignorato esempio più lungo ...]

Proprietà di sola lettura e sola scrittura

È necessario utilizzare una proprietà di sola lettura quando l'utente non può modificare il membro di dati logici della proprietà. Non utilizzare proprietà di sola scrittura.


Sì, il principio della minima sorpresa opera qui.
Paul Butcher,

6

Perché semplicemente non ha senso nella maggior parte dei casi. Quale proprietà potresti avere che puoi impostare ma non leggere?

Se OO è destinato a rappresentare meglio il mondo reale, è probabile che una proprietà solo set suggerisca che la tua modellazione è piuttosto scadente.

Modifica : vedi anche: /programming/4564928/are-set-only-properties-bad-practice che sostanzialmente dice che non è intuitivo e una proprietà solo set è sostanzialmente un metodo con un altro nome, quindi dovresti usare un metodo.


1
Ho usato proprietà solo set prima. Scrivono in un campo privato dell'oggetto per configurarne il comportamento. Sono utili quando il codice esterno non ha bisogno di conoscere il valore corrente, ma potrebbe essere necessario modificarlo. È raro, ovviamente, ma l'ho visto accadere.
Mason Wheeler,

@Mason - Certamente non mi spingerei mai a dire che non dovresti mai usarli ma dovrebbero essenzialmente essere l'eccezione piuttosto che la regola.
Jon Hopkins,

@MasonWheeler non è così approssimativamente Foo Foo { private get; set; }? Non chiamerei solo quella scrittura
Caleth,

6

Bene, immagino che se puoi impostare una proprietà su qualcosa senza mai ottenerla, non saprai mai se qualcos'altro cambia / sovrascrive il valore che hai impostato. Questo potrebbe essere un problema se fai affidamento sul valore impostato e non riesci (per qualche motivo) a persisterlo fino al momento in cui vorresti ottenerlo.

L'uso di un metodo anziché di una proprietà solo set sarà leggermente meno confuso per un utente. Il nome del metodo di solito indica set- o get- , ma i nomi delle proprietà normalmente non indicano che qualcosa può solo essere impostato e non ottenuto. Suppongo che se la proprietà fosse simile a "ReadOnlyBackgroundColour" non confonderebbe gli altri programmatori, ma sembrerebbe solo strano.


Sono d'accordo, ma come sarebbe diverso un metodo setter in questo caso?
Travis Christian,

1
@Travis Christian: Sembra che OP stia lavorando con una situazione in cui c'è un setter ma non getter. Quindi possono impostare qualcosa, ma non sapranno mai se cambia in seguito.
FrustratedWithFormsDesigner,

@Frustrato Ma non saprebbero nemmeno se qualcosa è stato nuovamente cambiato con un metodo.
Adam Lear

@Anna Lear ♦: Se c'è un getter, puoi almeno testare il valore prima di usarlo se hai un punto nel tuo codice in cui il valore che hai impostato potrebbe essere improvvisamente in dubbio.
FrustratedWithFormsDesigner,

3
@Frustrato sono d'accordo. È solo che la domanda riguardava l'uso di una proprietà solo set e l'utilizzo di un metodo per fare la stessa cosa.
Adam Lear

-1

Questo è un argomento molto vecchio, ma che è saltato alla mia vista in questa fase avanzata e vorrei alcuni commenti mentre provo a fare un caso per proprietà di sola scrittura ...

Ho un insieme di ActiveReportclassi che fanno parte di un sito Web che sono istanziate ed eseguite sul postback dopo una serie di selezioni dell'utente.

Il codice VB è simile al seguente:

  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

Questi report usano budella generiche, accettano CommonReaderuna procedura memorizzata e una matrice di SqlParametervalori predefiniti , ognuno dei quali ha una proprietà WriteOnly associata che, a seconda della progettazione del report, può essere passata come parametro all'istanza o impostata dall'utente dopo l'istanza prima chiamando il Runmetodo dei rapporti .

  '''''''''''''''''''''''
  ' 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()

Quindi, per come la vedo io, ho proprietà di sola scrittura in questo caso

  1. Consente un controllo del tipo più forte poiché SqlParameteri tipi sono generici
  2. Maggiore flessibilità nella creazione del report, il report può essere istanziato immediatamente se tutti i parametri sono disponibili o aggiunti successivamente non appena diventano disponibili.
  3. Le proprietà supportano la sintassi "Con" all'istanza
  4. Un "getter" è davvero necessario poiché i parametri sono noti all'utente e non modificati dal Rapporto?
  5. Poiché le SqlParameters sono classi e non valori primitivi, le proprietà WriteOnly consentono un'interfaccia più semplice per l'impostazione dei parametri

Quindi sono i miei pensieri.

Potrei invece convertirlo in un metodo? certo ma l'interfaccia sembra ... meno carina

  R2.BudgetID = SomeBudgetID

contro

  R2.SetBudgetID(SomeBudgetID)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.