Por que não é recomendável ter propriedade somente de configuração?

9

Hoje no trabalho, um dos meus colegas revisou meu código e sugeriu que eu removesse uma propriedade somente de conjunto e usasse um método.

Como estávamos ocupados com outras coisas, ele me disse para examinar a Property Designseção do livro "Framework Design Guidelines". No livro, o escritor disse apenas para evitar:

Propriedades com o setter com acessibilidade mais ampla que o getter

E agora estou me perguntando por que não é recomendável ter propriedade somente de conjunto? Alguém pode esclarecer para mim?

Prashant Cholachagudda
fonte
6
Você pode descrever a situação em que você pensou que uma propriedade somente de conjunto era apropriada? Isso pode tornar as respostas um pouco mais relevantes.
JohnFx 22/02
11
Estou tentando pensar em um exemplo que faz sentido semanticamente. A única coisa que vem à mente é uma Passwordpropriedade de uma Userclasse. Você pode configurá-lo, mas não pode obtê-lo. Você poderia ter uma HashedPasswordpropriedade somente leitura . Chamar o conjunto faria o hash e alteraria a HashedPasswordpropriedade. Eu não gritaria com você se você fizesse isso.
Scott Whitlock

Respostas:

15

Eu acho que isso pode ter a ver com expectativas. Propriedades apenas de conjunto são incomuns e geralmente são usadas para conjuntos "burros" apenas para armazenar um valor sem muito processamento. Se você trabalha muito em um levantador, é melhor usar um método - as pessoas esperam que os métodos levem muito tempo para serem executados e que possam ter efeitos colaterais. A implementação de comportamentos semelhantes em uma propriedade pode resultar em código que viola as expectativas.

Aqui está uma seção relevante das Diretrizes de uso da propriedade da Microsoft :

Propriedades vs. Métodos

Os designers da biblioteca de classes geralmente precisam decidir entre implementar um membro da classe como uma propriedade ou um método. Em geral, métodos representam ações e propriedades representam dados. Use as diretrizes a seguir para ajudá-lo a escolher entre essas opções.

  • Use uma propriedade quando o membro for um membro de dados lógicos. Nas seguintes declarações de membro, Nameé uma propriedade porque é um membro lógico da classe.
public string Name
{
    get 
    {
        return name;
    }
    set 
    {
        name = value;
    }
}

Use um método quando:

  • A operação é uma conversão, como Object.ToString.
  • A operação é cara o suficiente para que você queira se comunicar com o usuário para que ele considere o armazenamento em cache do resultado.
  • Obter um valor de propriedade usando o getacessador teria um efeito colateral observável.
  • Ligar para o membro duas vezes seguidas produz resultados diferentes.
  • A ordem de execução é importante. Observe que as propriedades de um tipo devem poder ser definidas e recuperadas em qualquer ordem.
  • O membro é estático, mas retorna um valor que pode ser alterado.
  • O membro retorna uma matriz. As propriedades que retornam matrizes podem ser muito enganadoras. Geralmente é necessário retornar uma cópia da matriz interna para que o usuário não possa alterar o estado interno. Isso, juntamente com o fato de que um usuário pode facilmente assumir que é uma propriedade indexada, leva a um código ineficiente. No exemplo de código a seguir, cada chamada para a propriedade Methods cria uma cópia da matriz. Como resultado, 2 ^ n + 1 cópias da matriz serão criadas no seguinte loop.
Type type = // Get a type.
for (int i = 0; i < type.Methods.Length; i++)
{
   if (type.Methods[i].Name.Equals ("text"))
   {
      // Perform some operation.
   }
}

[... pulou um exemplo mais longo ...]

Propriedades somente leitura e somente gravação

Você deve usar uma propriedade somente leitura quando o usuário não puder alterar o membro de dados lógicos da propriedade. Não use propriedades somente gravação.

Adam Lear
fonte
Sim - o princípio da menor surpresa opera aqui.
Paul Butcher
6

Porque simplesmente não faz sentido na maioria dos casos. Que propriedade você pode ter, que pode definir, mas não pode ler?

Se o OO tiver a intenção de representar melhor o mundo real, é provável que uma propriedade definida apenas sugira que a sua modelagem esteja bem.

Edit : Veja também: /programming/4564928/are-set-only-properties-bad-practice, que essencialmente diz que não é intuitivo e que uma propriedade set only é basicamente um método com outro nome, portanto, você deve usar um método.

Jon Hopkins
fonte
11
Eu usei propriedades somente de conjunto antes. Eles gravam em um campo privado do objeto para configurar seu comportamento. Eles são úteis quando o código externo não precisa saber o valor atual, mas pode precisar alterá-lo. Isso é raro, é claro, mas eu já vi isso acontecer.
Mason Wheeler
@Mason - Eu certamente nunca chegaria a dizer que você nunca deveria usá-los, mas eles deveriam ser essencialmente a exceção e não a regra.
Jon Hopkins
@MasonWheeler não é aproximadamente Foo Foo { private get; set; }? Eu não chamaria isso apenas de escrita
Caleth 16/01
6

Bem, imagino que, se você pode definir uma propriedade em algo, mas nunca obtê-lo, nunca saberá se alguma outra coisa altera / substitui o valor que você definiu. Isso pode ser um problema se você confiar no valor definido e não conseguir (por algum motivo) persistir até o momento em que deseja obtê-lo.

Usar um método em vez de uma propriedade somente de conjunto será um pouco menos confuso para um usuário. O nome do método geralmente indica set- ou get- , mas os nomes das propriedades normalmente não indicam que algo pode ser definido e não obtido. Suponho que se a propriedade fosse algo como "ReadOnlyBackgroundColour", não seria confuso para outros codificadores, mas isso pareceria estranho.

FrustratedWithFormsDesigner
fonte
Eu concordo, mas como um método setter seria diferente nesse caso?
Travis Christian
11
@ Travis Christian: Parece que o OP está trabalhando com uma situação em que existe um levantador, mas não um levantador. Para que eles possam definir algo, mas nunca saberão se isso muda mais tarde.
FrustratedWithFormsDesigner
@ Frustrated Mas eles também nunca saberiam se algo foi alterado novamente com um método.
Adam Lear
@ Anna Lear ♦: Se houver um getter, você pode pelo menos testar o valor antes de usá-lo, se tiver um ponto em seu código em que o valor que você definiu possa estar subitamente em dúvida.
FrustratedWithFormsDesigner
3
@ Frustrado, eu concordo. É que a pergunta era sobre o uso de uma propriedade somente de conjunto versus o uso de um método para fazer a mesma coisa.
Adam Lear
-1

Este é um tópico muito antigo, mas que surgiu na minha opinião neste estágio final e eu gostaria de alguns comentários enquanto tentava defender propriedades somente para gravação ...

Eu tenho um conjunto de ActiveReportclasses que fazem parte de um site que são instanciadas e executadas na postagem após várias seleções de usuários.

O código VB é mais ou menos assim:

  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

Esses relatórios usam tripas genéricas, usam CommonReaderum procedimento armazenado e uma matriz de SqlParameters padrão , cada um dos quais possui uma propriedade WriteOnly associada que, dependendo do design do relatório, pode ser transmitida como parâmetro na instanciação ou definida pelo usuário após instanciação antes chamando o Runmétodo de relatórios .

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

Então, a meu ver, ter propriedade somente gravação neste caso

  1. Permite uma verificação de tipo mais forte, já que SqlParameters são genéricos
  2. Mais flexibilidade na criação do relatório, o relatório pode ser instanciado imediatamente se todos os parâmetros estiverem disponíveis ou adicionados posteriormente, à medida que estiverem disponíveis.
  3. Propriedades suportam sintaxe "With" na instanciação
  4. Um "getter" é realmente necessário, pois os parâmetros são conhecidos pelo usuário e não são alterados pelo relatório?
  5. Como SqlParameters são classes e não valores primitivos, as Propriedades WriteOnly permitem uma interface mais simples para a configuração de parâmetros

Então esse é o meu pensamento.

Eu poderia convertê-lo em um método? claro, mas a interface parece ... menos agradável

  R2.BudgetID = SomeBudgetID

versus

  R2.SetBudgetID(SomeBudgetID)
fnostro
fonte