una tag que propiedades propiedad programacion metodos entre diferencia descriptores clase campo acceso c# properties

c# - tag - Propiedades de solo escritura, ¿cuál es el punto?



que es get en programacion (9)

Esta pregunta ya tiene una respuesta aquí:

Entiendo por qué querría usar una propiedad de solo lectura con la siguiente sintaxis:

private int _MyInt; public int MyInt { get { return _MyInt; } }

Probablemente este ejemplo no sea el mejor porque creo que las propiedades de solo lectura realmente brillan en conjunto con una variable de readonly , pero eso no viene al caso. Lo que no entiendo es por qué usar una propiedad de solo escritura con la siguiente sintaxis:

private int _MyInt; public int MyInt { set { _MyInt = value; } }

Así es como se describen las propiedades de solo lectura en varios libros y tutoriales. Si configura la variable, la leería conceptualmente en algún punto, al menos internamente a la clase, pero para leerla incluso internamente dentro de la clase, lo haría accediendo a _MyInt que creo que viola el espíritu de encapsulación que las propiedades intentan hacer cumplir. En su lugar, ¿por qué no utilizaría toda la potencia de la propiedad con distintas modificaciones de acceso para acceder a ella como tal?

private int _MyInt; public int MyInt { set { _MyInt = value; } private get { return _MyInt; } }

Que por supuesto solo se puede escribir

public int MyInt { set; private get; }

Aún obtiene la encapsulación, pero restringe el acceso de otras clases, por lo que aún es de solo escritura para clases externas.

A menos que exista un caso en el que, honestamente, querría asignar una variable pero nunca acceder a ella, en ese caso, definitivamente me gustaría saber cuándo surgiría esta necesidad.


Cualquier información que deba fluir de una manera es útil a través de una propiedad de solo escritura. En general, escribimos clases para que la información fluya desde o hacia adentro y hacia afuera. En el caso de solo escritura, debe pensar en situaciones en las que la información solo debe fluir hacia adentro y no hacia afuera. Por lo general, esto implica un tipo de información de seguridad porque no queremos que un consumidor tenga acceso para recuperar una información segura. Contraseñas, números CC, etc ...

Cuando la información no es segura, por ejemplo, cuando no nos importa que nadie acceda a ella, obtenemos el patrón común de obtener / establecer. 99.9% de las veces es así como se usan las propiedades. Ya que hay otras formas, tan fácil que puede ser más robusta para lograr esto, esta es más una construcción semántica que se dejó por simetría que cualquier otra cosa. Uno de los casos raros en los que algo no se eliminó y usted se fue con "¿Por qué diablos lo eliminaron?".


Estoy seguro de que la función está ahí simplemente para simetría con una variable de solo obtención. Como lo indica vagamente Aphex, algunas cosas no tienen sentido y solo están ahí porque es más fácil dejarlo en lugar de eliminarlo.


He tenido motivos para una propiedad de solo escritura.

En un servicio web .NET he tenido que crear un servicio web .ASMX heredado, ya que el URI está codificado en hardware.

Soy un gran fan de usar Ninject para la inyección de dependencia, usar la inyección de constructor para satisfacer todas las dependencias que pueda tener una clase. En su mayor parte, estas dependencias se declararán private readonly fieldName y se asignarán a en el constructor. La razón de esto es que las dependencias de la clase no son parte de las responsabilidades de la clase, son dependencias.

Sin embargo, el problema es que el mecanismo de fábrica que ASP.NET utiliza para crear la instancia de clase para un servicio web depende de que exista un constructor sin argumentos, que dañó mi inyección de constructor.

Podría haber usado una llamada del constructor predeterminado para redirigir a un constructor sobrecargado que utiliza un patrón (anti) ServiceLocator, pero eso no me gustó.

Usando la extensión web Ninject, heredé mi clase de servicio de Ninject.Web.WebServiceBase y Ninject.Web.WebServiceBase inyección de propiedades, marcando las propiedades que Ninject satisfaría con un atributo [Inject] .

Volviendo al tema de que los servicios inyectados son dependencias para la clase, en lugar de las responsabilidades que tiene la clase, no quiero que otras clases accedan a estas dependencias, por lo que marco la propiedad get como privada.


Interesante pregunta.

Después de algunas búsquedas en Google, this es todo lo que pude encontrar: una propiedad de solo escritura podría usarse para establecer una contraseña en un objeto User . Dado que las contraseñas generalmente se almacenan en forma de hash, no hay (y debería haber) ninguna forma de recuperar una contraseña después de que se haya establecido.


La razón por la que puedo pensar en la parte superior de mi cabeza es que _myInt aparece en la parte superior del menú de contexto inteligente.

No creo que acceder a _myInt viole el espíritu de encapsulación en absoluto; Es un campo miembro privado de una clase. Cualquier código dentro de la clase DEBE usar el _myInt. Es privado, después de todo.

Lo único que le importa al mundo exterior es el contrato público de la clase. _myInt es una preocupación de la clase en sí, no es parte del contrato público.

Y como dije, es más fácil tomar _myInt con inteligencia cuando estás programando.


Las fuentes que he leído han sugerido que si honestamente tiene una situación en la que acaba de crear una propiedad de solo escritura, probablemente debería considerar convertirla en un método. Y típicamente estoy de acuerdo.


Nunca he encontrado un caso de uso válido para una propiedad de solo escritura. Honestamente, si hay un caso de uso válido para una propiedad de solo escritura, creo que es seguro decir que la solución está mal diseñada.

Si necesita semántica de "solo escritura", debe utilizar un método. Por ejemplo, otro usuario ha encontrado un ejemplo de un objeto de usuario que utiliza una propiedad de solo escritura para establecer una contraseña. Este es un mal diseño:

class User { public string Password { set { /* password encryption here */ } } }

Ugh Esto es mucho mejor:

class User { public void SetPassword(string password) { /* password encryption here */ } }

Ver, una propiedad de lectura / escritura es un conjunto de métodos que están diseñados para enmascararse como un campo. Se ven y se sienten como un campo. Es por esta razón que una propiedad de solo lectura tiene sentido porque estamos acostumbrados a tener campos y variables que podemos leer pero que no podemos cambiar. Sin embargo, no hay un campo correspondiente o construcción de variable que se pueda escribir pero no se pueda leer.

Por eso creo que crear una API que emplee propiedades de solo escritura es una mala práctica. Se ejecuta de manera contraintuitiva a lo que creo que es el objetivo principal de la sintaxis de propiedad en C #.

Edit: Más filosofía ... Creo que las clases tienen un propósito funcional: proporcionan un contenedor para que los datos relacionados se conserven y manipulen. Tome nuestra clase de User , por ejemplo, esta clase contendrá toda la información que pertenece a un usuario en el sistema. Recopilamos todos estos datos y les damos un nombre único: usuario . De esta manera usamos clases para crear abstracciones . User es una abstracción que nos permite razonar sobre todos los datos individuales que conforman un usuario (contraseña, nombre, fecha de nacimiento, etc.).

Ahora hay buenas abstracciones y hay malas abstracciones. Creo que las propiedades de solo escritura son malas abstracciones porque está permitiendo que alguien ingrese datos y no los lea. ¿Por qué rechazarías esto? Probablemente porque la información que se ha pasado se ha transformado de alguna manera que hace que sea ilegible para el pasador.

Por lo tanto, esto significa que una propiedad de solo escritura, por definición, debe crear efectos secundarios que la persona que llama no puede ver (porque si pudieran verlos, no habría ninguna razón para que la propiedad sea de solo escritura). El mejor constructo en el lenguaje C # para establecer un valor con efectos secundarios es el método .

Recomendaría encarecidamente no usar propiedades de solo escritura porque los consumidores de su API las encontrarán confusas y frustrantes. Incluso si encuentra un caso de uso válido para esta sintaxis, no justifica su uso.

Edición: aquí hay una recomendación oficial de .Net Framework Design Guidelines para desarrollar bibliotecas de clases -> Member Design Guidelines -> Property Design

No proporcione propiedades de sólo conjunto.

Si no se puede proporcionar la propiedad getter, use un método para implementar la funcionalidad en su lugar. El nombre del método debe comenzar con Set seguido de lo que habría sido el nombre de la propiedad ...


Un caso común que puedo ver es si solo desea que una persona que llama pueda obtener una versión transformada de su propiedad. Por ejemplo:

public int MyInt { set; } public string MyIntAsString { get { return this.MyInt.ToString(); } }

Obviamente, este no es un ejemplo real, pero te haces una idea.

EDITAR :

Después de leer el caso de uso de ejemplo de Thomas, entonces un escenario de tipo de "transformación" real podría ser recuperar una versión cifrada de la propiedad de solo escritura:

private string password; public string ClearPassword { set { this.password = value; } public string EncryptedPassword { get { return Encrypt(password); } }


Un uso para una propiedad de solo escritura es para admitir la inyección de dependencia de establecedor.

Digamos que tuve una clase:

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

El WhizbangProvider no está diseñado para ser accedido por el mundo exterior. Nunca querría interactuar con el service.Provider . service.Provider , es demasiado complejo. Necesito una clase como WhizbangService para actuar como una fachada. Sin embargo, con el setter, puedo hacer algo como esto:

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

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

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

Y así....