¿Por qué no se recomienda tener una propiedad de solo conjunto?

9

Hoy, en el trabajo, uno de mis colegas revisó mi código y sugirió que eliminara una propiedad de solo conjunto y utilizara un método.

Como ambos estábamos ocupados con otras cosas, me dijo que mirara la Property Designsección del libro "Pautas de diseño del marco". En el libro, el escritor acaba de decir que evite:

Propiedades con el setter que tiene una accesibilidad más amplia que el getter

Y ahora me pregunto por qué no se recomienda tener una propiedad de solo conjunto. ¿Alguien puede aclararme?

Prashant Cholachagudda
fuente
66
¿Puede describir la situación en la que pensó que una propiedad de solo conjunto era apropiada? Podría hacer que las respuestas sean un poco más relevantes.
JohnFx
1
Estoy tratando de pensar en un ejemplo que tenga sentido semánticamente. Lo único que viene a la mente es una Passwordpropiedad en una Userclase. Puede configurarlo, pero no puede obtenerlo. Entonces podría tener una HashedPasswordpropiedad de solo lectura . Llamar al conjunto haría el hash y cambiaría la HashedPasswordpropiedad. No te gritaría si hicieras eso.
Scott Whitlock

Respuestas:

15

Creo que puede tener que ver con las expectativas. Las propiedades de solo conjunto son poco comunes y las propiedades se usan generalmente para conjuntos "tontos" solo para almacenar un valor sin mucho procesamiento. Si está haciendo mucho trabajo en un setter, es mejor usar un método: las personas esperan que los métodos tarden mucho tiempo en ejecutarse y que tengan efectos secundarios. La implementación de un tipo similar de comportamiento en una propiedad puede generar un código que viola las expectativas.

Aquí hay una sección relevante de las Pautas de uso de propiedades de Microsoft :

Propiedades versus métodos

Los diseñadores de bibliotecas de clases a menudo deben decidir entre implementar un miembro de la clase como una propiedad o un método. En general, los métodos representan acciones y las propiedades representan datos. Use las siguientes pautas para ayudarlo a elegir entre estas opciones.

  • Use una propiedad cuando el miembro sea un miembro de datos lógico. En las siguientes declaraciones de miembros, Namees una propiedad porque es un miembro lógico de la clase.
public string Name
{
    get 
    {
        return name;
    }
    set 
    {
        name = value;
    }
}

Use un método cuando:

  • La operación es una conversión, como Object.ToString.
  • La operación es lo suficientemente costosa como para que desee comunicar al usuario que debería considerar el almacenamiento en caché del resultado.
  • Obtener un valor de propiedad usando el getdescriptor de acceso tendría un efecto secundario observable.
  • Llamar al miembro dos veces seguidas produce resultados diferentes.
  • El orden de ejecución es importante. Tenga en cuenta que las propiedades de un tipo deben poder establecerse y recuperarse en cualquier orden.
  • El miembro es estático pero devuelve un valor que se puede cambiar.
  • El miembro devuelve una matriz. Las propiedades que devuelven matrices pueden ser muy engañosas. Por lo general, es necesario devolver una copia de la matriz interna para que el usuario no pueda cambiar el estado interno. Esto, junto con el hecho de que un usuario puede asumir fácilmente que es una propiedad indexada, conduce a un código ineficiente. En el siguiente ejemplo de código, cada llamada a la propiedad Métodos crea una copia de la matriz. Como resultado, se crearán 2 ^ n + 1 copias de la matriz en el siguiente bucle.
Type type = // Get a type.
for (int i = 0; i < type.Methods.Length; i++)
{
   if (type.Methods[i].Name.Equals ("text"))
   {
      // Perform some operation.
   }
}

[... omitido ejemplo más largo ...]

Propiedades de solo lectura y de solo escritura

Debe usar una propiedad de solo lectura cuando el usuario no pueda cambiar el miembro de datos lógicos de la propiedad. No use propiedades de solo escritura.

Adam Lear
fuente
Sí, el principio de menor sorpresa opera aquí.
Paul Butcher
6

Porque simplemente no tiene sentido en la mayoría de los casos. ¿Qué propiedad podría tener que pueda establecer pero no leer?

Si OO está destinado a representar mejor el mundo real, es probable que una propiedad de conjunto único sugiera que su modelado es bastante incorrecto.

Editar : Consulte también: /programming/4564928/are-set-only-properties-bad-practice que esencialmente dice que no es intuitivo y que una propiedad de solo conjunto es básicamente un método con otro nombre, por lo que debe usar un método.

Jon Hopkins
fuente
1
He usado propiedades de solo set antes. Escriben en un campo privado del objeto para configurar su comportamiento. Son útiles cuando el código externo no necesita conocer el valor actual, pero podría necesitar cambiarlo. Eso es raro, por supuesto, pero lo he visto suceder.
Mason Wheeler
@Mason - Ciertamente nunca iría tan lejos como para decir que nunca deberías usarlos, pero esencialmente deberían ser la excepción y no la regla.
Jon Hopkins
@MasonWheeler no es eso aproximadamente Foo Foo { private get; set; }? No llamaría a eso solo escribir
Caleth
6

Bueno, me imagino que si puede establecer una propiedad en algo pero nunca obtenerla, nunca sabrá si algo más cambia / sobrescribe el valor que estableció. Eso podría ser un problema si confía en el valor que establece y no puede (por alguna razón) persistir hasta el momento en que desea obtenerlo.

El uso de un método en lugar de una propiedad de solo conjunto será un poco menos confuso para un usuario. El nombre del método generalmente indica set- o get- , pero los nombres de propiedad normalmente no indican que algo solo se puede establecer y no obtener. Supongo que si la propiedad fuera algo así como "ReadOnlyBackgroundColour" no sería confuso para otros codificadores, pero eso se vería raro.

FrustratedWithFormsDesigner
fuente
Estoy de acuerdo, pero ¿cómo sería diferente un método setter en este caso?
Travis Christian
1
@Travis Christian: Parece que OP está trabajando con una situación en la que hay un setter pero no getter. Para que puedan configurar algo, pero nunca sabrán si cambia más tarde.
FrustratedWithFormsDesigner
@ Frustrado Pero tampoco sabrían si algo fue cambiado nuevamente con un método.
Adam Lear
@Anna Lear ♦: Si hay un captador, al menos puede probar el valor antes de usarlo si tiene un punto en su código donde el valor que ha establecido puede estar repentinamente en duda.
FrustratedWithFormsDesigner
3
@ Frustrado, estoy de acuerdo. Es solo que la pregunta era sobre el uso de una propiedad de solo conjunto frente al uso de un método para hacer lo mismo.
Adam Lear
-1

Este es un tema muy antiguo, pero que ha saltado a mi vista en esta etapa tardía y me gustaría algunos comentarios mientras trato de defender las propiedades de solo escritura ...

Tengo un conjunto de ActiveReportclases que forman parte de un sitio web que se instancian y se ejecutan en la devolución de datos después de varias selecciones de usuarios.

El código VB se parece a esto:

  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

Estos informes usan agallas genéricas, CommonReadertoman un procedimiento almacenado y una matriz de SqlParametercorreos predeterminados , cada uno de los cuales tiene una propiedad WriteOnly asociada que, según el diseño del informe, podría pasar como un parámetro en la creación de instancias o establecido por el usuario después de la creación de instancias antes llamando al Runmétodo de informes .

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

Entonces, como lo veo, tener propiedad de solo escritura en este caso

  1. Permite una verificación de tipo más fuerte ya que los SqlParameters son genéricos
  2. Más flexibilidad para crear el informe, el informe se puede instanciar de inmediato si todos los parámetros están disponibles o se agregan después a medida que estén disponibles.
  3. Las propiedades admiten la sintaxis "Con" en la instanciación
  4. ¿Es realmente necesario un "captador" ya que el Informe conoce los parámetros y el Informe no los altera?
  5. Dado que los SqlParameters son clases y no valores primitivos, las propiedades WriteOnly permiten una interfaz más simple para configurar parámetros

Así que esos son mis pensamientos.

¿Podría convertirlo a un método en su lugar? seguro, pero la interfaz parece ... menos agradable

  R2.BudgetID = SomeBudgetID

versus

  R2.SetBudgetID(SomeBudgetID)
fnostro
fuente