oop properties language-agnostic

oop - ¿Las propiedades de solo escritura tienen aplicaciones prácticas?



properties language-agnostic (14)

Aunque las directrices de diseño de .NET recomiendan utilizar un método ("SetMyWriteOnlyParameter") en lugar de una propiedad de solo escritura, las propiedades de escritura solo me resultan útiles al crear objetos vinculados a partir de una representación serializada (desde una base de datos).

Nuestra aplicación representa sistemas de producción de yacimientos petrolíferos. Tenemos el sistema como un todo (el objeto "Modelo") y varios objetos de Reservorio, Bien, Nodo, Grupo, etc.

El Modelo se crea y lee primero de la base de datos; los demás objetos necesitan saber a qué modelo pertenecen. Sin embargo, el modelo necesita saber qué objeto inferior representa el total de ventas. Tiene sentido que esta información se almacene como una propiedad de Modelo. Si no queremos tener que hacer dos lecturas de información del Modelo, necesitamos poder leer el nombre del objeto Ventas antes de su creación. Luego, posteriormente, establecemos la variable "SalesObject" para que apunte al objeto real (de modo que, por ejemplo, cualquier cambio por parte del usuario del nombre de este objeto no causa problemas)

Preferimos usar una propiedad de solo escritura - ''SalesObjectName = "TopNode"'' - en lugar de un método - ''SetSalesObjectName ('' TopNode '') - porque nos parece que este último sugiere que existe SalesObject.

Este es un punto menor, pero suficiente para hacernos desear usar una propiedad de solo escritura.

No sé por qué comencé a pensar en esto, pero ahora parece que no puedo parar.

En C #, y probablemente en muchos otros idiomas, recuerdo que Delphi solía permitirte hacer esto también, es legal escribir esta sintaxis:

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

En otras palabras, la propiedad tiene un setter pero no getter , es solo de escritura .

Supongo que no puedo pensar en ninguna razón por la que esto debería ser ilegal , pero nunca lo he visto en la naturaleza, y parezco un código bastante brillante / horrible en la naturaleza. Parece un olor a código; parece que el compilador debería darme una advertencia:

CS83417: La propiedad ''Nombre'' parece ser completamente inútil y estúpida. ¡Mal programador! Considere reemplazar con un método.

Pero tal vez simplemente no he estado haciendo esto el tiempo suficiente, o he estado trabajando en un campo demasiado estrecho para ver ejemplos del uso efectivo de tal construcción.

¿Hay ejemplos de la vida real de propiedades de solo escritura que no pueden ser reemplazados por llamadas a métodos directos o serían menos intuitivos?


Bueno, técnicamente no hay nada de malo en una propiedad exclusiva de Setter. El Organizador podría hacer alguna validación, y tal vez otros métodos, públicos o privados, podrían depender de ello.

Por ejemplo:

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

Entonces la declaración en sí misma puede ser legal y válida. Sin embargo, el cuerpo de su método es un gran olor a código, pero ese no es el trabajo de los compiladores.


Code Analysis (también conocido como FxCop) le proporciona un diagnóstico:

CA1044 : Microsoft.Design: como la propiedad ''WeirdClass.Name'' es de solo escritura, agregue un getter de propiedades con una accesibilidad que sea mayor o igual que su setter o convierta esta propiedad en un método.


En el patrón de MVP, es común escribir una propiedad con un setter en la vista (sin necesidad de un getter): cada vez que el presentador lo configura, la propiedad usará ese valor para actualizar algún elemento de UI.

Vea here para una pequeña demostración:

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.ToString(); } } }

El método del presentador InitView simplemente establece el valor de la propiedad:

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


En lo que a mí respecta, no lo hacen. Cada vez que he usado una propiedad de solo escritura como un truco rápido, luego me arrepiento. Por lo general, termino con un constructor o una propiedad completa.

Por supuesto que estoy tratando de demostrar que es negativo, así que tal vez haya algo que me falta.


Hacer algo de solo escritura es útil siempre que no se supone que debes leer lo que escribes.

Por ejemplo, al dibujar cosas en la pantalla (esto es precisamente lo que hace el Administrador de ventanas del escritorio en Windows):
Sin duda, puede dibujar en una pantalla, pero nunca debe volver a leer los datos (y mucho menos esperar obtener el mismo diseño que antes).

Ahora bien, si las propiedades de solo escritura son útiles (a diferencia de los métodos), no estoy seguro de la frecuencia con que se usan. Supongo que se puede imaginar una situación con una propiedad "BackgroundColor", donde escribir establece el color de fondo de la pantalla, pero la lectura no tiene sentido (necesariamente).
Así que no estoy seguro de esa parte, pero en general solo quería señalar que hay casos de uso para situaciones en las que solo escribe datos y nunca los lee.


Las propiedades de solo escritura son bastante útiles y las uso con frecuencia. Se trata de la encapsulation , lo que restringe el acceso a los componentes de un objeto. A menudo necesita proporcionar uno o más componentes a una clase que necesita usar internamente, pero no hay razón para hacerlos accesibles a otras clases. Hacerlo solo hace que su clase sea más confusa ("¿uso este getter o este método?"), Y es más probable que su clase sea manipulada o tenga su propósito real pasado por alto.

Consulte "Por qué los métodos getter y setter son malos" para una discusión interesante de esto. No soy tan duro como el escritor del artículo, pero creo que es bueno pensar en ello. Normalmente uso setters pero rara vez uso getters.


Mi primera reacción a esta pregunta fue: "¿Qué tal un método java.util.Random#setSeed ?"

Creo que las propiedades solo de escritura son útiles en varios escenarios. Por ejemplo, cuando no desea exponer la representación interna ( encapsulación ), mientras permite cambiar el estado del objeto. java.util.Random es un muy buen ejemplo de dicho diseño.


No puedo dejar de pensar en esto, tampoco. Tengo un caso de uso para una propiedad de "solo escritura". No puedo ver una buena salida.

Quiero construir un atributo C # que se deriva de AuthorizeAttribute para una aplicación ASP.NET MVC. Tengo un servicio (digamos, IStore) que devuelve información que ayuda a decidir si el usuario actual debe ser autorizado. Constructor Injection no funcionará, ya que

public AllowedAttribute: AuthorizeAttribute { public AllowedAttribute(IStore store) {...} private IStore Store { get; set; } ... }

hace que la tienda sea un parámetro de atributo posicional, pero IStore no es un tipo de parámetro de atributo válido, y el compilador no compilará el código anotado con ella. Estoy obligado a recurrir a Property Setter Injection.

public AllowedAttribute: AuthorizeAttribute { [Inject] public IStore Store { private get; set; } ... }

Junto con todas las otras cosas malas sobre Property Setter en lugar de Constructor Injection, el servicio es una propiedad de solo escritura. Ya es suficientemente malo que tengo que exponer al colocador a clientes que no deberían necesitar conocer los detalles de la implementación. No haría ningún favor a nadie para permitir que los clientes vean al comprador también.

Creo que el beneficio de Dependency Injection supera las directrices contra las propiedades de solo escritura para este escenario, a menos que me falta algo.


No, no puedo imaginar ningún caso donde no puedan ser reemplazados, aunque podría haber personas que los consideren más legibles.

Caso hipotético:

CommunicationDevice.Response = "Hello, World"

en lugar de

CommunicationDevice.SendResponse("Hello, World")

El trabajo principal sería realizar efectos secundarios IO o validación.

Curiosamente, VB .NET incluso obtuvo su propia palabra clave para este raro tipo de propiedad;)

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

a pesar de que muchas propiedades "de solo escritura" del exterior en realidad tienen un getter privado.


Recientemente trabajé en una aplicación que maneja contraseñas. (Tenga en cuenta que no estoy afirmando que la siguiente es una buena idea, solo estoy describiendo lo que hice).

Tenía una clase, HashingPassword , que contenía una contraseña. El constructor tomó una contraseña como argumento y la almacenó en un atributo privado. Dado uno de estos objetos, puede adquirir un hash salado para la contraseña o verificar la contraseña contra un hash salado dado. Por supuesto, no había forma de recuperar la contraseña de un objeto HashingPassword .

Entonces tuve otro objeto, no recuerdo lo que era; pretendamos que era un plátano protegido con contraseña. La clase Banana tenía una propiedad de solo conjunto llamada Password , que creaba una HashingPassword partir del valor dado y la almacenaba en un atributo privado de Banana . Como el atributo de password de HashingPassword era privado, no había forma de escribir un getter para esta propiedad.

Entonces, ¿por qué tengo una propiedad solo de conjunto llamada Password lugar de un método llamado SetPassword ? Porque tiene sentido. El efecto fue, de hecho, establecer la contraseña de Banana , y si quería establecer la contraseña de un objeto Banana , esperaría hacer eso configurando una propiedad, no llamando a un método.

Usar un método llamado SetPassword no tendría inconvenientes importantes. Pero tampoco veo ninguna ventaja significativa.


Sé que esto ha estado aquí por mucho tiempo, pero lo encontré y tengo un caso de uso (imho) válido:

Cuando publicas parámetros en una llamada webapi desde ajax, simplemente puedes intentar completar las propiedades de la clase de parámetros e incluir la validación o cualquier otra cosa.

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; } } } }

En JavaScript, simplemente puede completar los parámetros, incluida la validación:

var callparameter = { TryMyIntPropertyForAjax = 23 }

lo cual es seguro en este ejemplo, pero si maneja la entrada de usuario, podría no estar seguro de tener un intvalue válido o algo similar.


Tengo un código similar al siguiente en un proyecto XNA. Como puede ver, Scale es de solo escritura, es útil y (razonablemente) intuitivo y una propiedad de lectura ( get ) no tendría sentido. Claro que podría reemplazarse con un método, pero me gusta la sintaxis.

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... }


Un uso para una propiedad de solo escritura es admitir la inyección de dependencia del colocador, que normalmente se usa para los parámetros opcionales.

Digamos que tuve una clase:

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

The WhizbangProvider no está destinado a ser accedido por el mundo exterior. Nunca me gustaría interactuar con el service.Provider . service.Provider , es demasiado complejo. Necesito una clase como WhizbangService para actuar como fachada. Sin embargo, con el colocador, puedo hacer algo como esto:

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

Y el servicio inicia una exhibición de fuegos artificiales. O tal vez prefiera ver un espectáculo de agua y luz:

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

Y así....

Esto se vuelve especialmente útil si la propiedad se define en una clase base. Si elige la inyección de construcción para esta propiedad, necesitaría escribir una sobrecarga del constructor en cualquier clase derivada.

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

Aquí, la alternativa con inyección de constructor es:

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) { } }

En mi opinión, este enfoque es más desordenado, porque necesita algo del funcionamiento interno de la clase, específicamente, que si pasa el null al constructor, obtendrá un valor predeterminado razonable.