2011-01-14 12 views
46

entiendo por qué desea utilizar una propiedad de sólo lectura utilizando la siguiente sintaxis:Propiedades de escritura, ¿cuál es el punto?

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

En este ejemplo, probablemente no es el mejor, porque creo que las propiedades de sólo lectura realmente brillan en conjunción con una readonly variable, pero eso está al lado del punto. Lo que no entiendo es por qué utilizar una propiedad de sólo escritura utilizando la siguiente sintaxis:

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

Es así como propiedades de sólo lectura se describen en diversos libros y tutoriales. Si configura la variable, leería conceptualmente en un punto de, al menos internamente a la clase, pero para leerlo incluso internamente dentro de la clase, lo haría al acceder al _MyInt que creo que viola el espíritu de encapsulado cuyas propiedades intenta hacer cumplir. En su lugar, ¿por qué no sólo tiene que utilizar toda la potencia de la propiedad con diferentes modifica de acceso para acceder a él como tal:

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

Lo que por supuesto solo se puede escribir

public int MyInt { set; private get; } 

sigue recibiendo el encapsulación, pero restringe el acceso a otras clases, por lo que sigue siendo de escritura solo para clases externas.

A menos que exista un caso en el que honestamente quiera asignar una variable pero nunca tener acceso a ella, en cuyo caso me gustaría saber cuándo surgirá esta necesidad.

+5

Si no desea utilizar una sintaxis en particular, puede hacerlo. –

+0

Al menos con WPF y el patrón MVVM, puede exponer una propiedad en ViewModel destinada a un enlace 'OneWayToSource' en la vista. En este caso, solo necesitarías el colocador. Pero no impide tener un getter, también, y de hecho sería inofensivo (y probablemente útil) incluirlo de todos modos. Entonces quizás eso todavía no se aplique ... –

+2

'if (False)'. ¿Cuál es el punto de? – Aphex

Respuesta

62

Nunca me he encontrado con 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 usar 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 */ 
    } 
} 

Sede, una propiedad de lectura/escritura es un conjunto de métodos que están diseñados para hacerse pasar por 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 no podemos cambiar. Sin embargo, no existe una construcción de campo o variable correspondiente que sea escribible pero no legible.

Es por eso que creo que crear una API que emplee propiedades de solo escritura es una mala práctica. Funciona contra la intuición de lo que creo que es el objetivo principal de la sintaxis de la propiedad en C#.

Editar: Más filosofía ... Creo que las clases tienen un propósito funcional: proporcionan un contenedor para almacenar y manipular los datos relacionados. Tome nuestra clase 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 forma usamos clases para crear abstracciones.User es una abstracción que nos permite razonar sobre todos los datos individuales que componen 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é no permitirías esto? Lo más probable es que la información que ha sido transmitida se haya transformado de alguna manera que la haga ilegible para el transeúnte.

Esto significa que una propiedad de solo escritura por definición debe crear efectos colaterales que la persona que llama no puede ver (porque si pudieran verlos no habría razón para escribir solo la propiedad). La mejor construcción en el lenguaje C# para establecer un valor con efectos secundarios es el método.

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


Editar: Aquí está la recomendación oficial del .Net Framework Design Guidelines for Developing Class Libraries -> Member Design Guidelines -> Property Design

no proporcionan propiedades de configuración solamente.

Si no se puede proporcionar el captador de propiedades, utilice un método para implementar la funcionalidad . El nombre del método debe comenzar con el conjunto seguido de lo que habría sido el nombre de propiedad ...

+2

Estoy de acuerdo: si tiene alguna información que debe ingresar, pero no debe leerse solo use un método. – Neil

+0

¿Puede proporcionar algún razonamiento detrás de esto? ¿Qué sucede si desea tener un enlace de un solo sentido desde un formulario a un objeto Usuario que le permite establecer la contraseña? – Jake

+1

Gracias por la respuesta. Esto fue principalmente un tipo de pregunta "simplemente curiosa", y estoy contento con la cantidad de respuesta y pensamiento que obtuvo. Me gustó especialmente la filosofía adicional que brindó. – Anthony

5

Un caso común que puedo ver es si sólo quería una persona que llama a ser capaz de 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 se entiende la situación.

EDITAR:

Después de leer el caso ejemplo, el uso de Thomas, a continuación, una verdadera 'transformación' escenario tipo podría ser para recuperar una versión encriptada de la propiedad de sólo escritura:

private string password; 

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

Si MyInt solo tiene setter, no puede llamar a this.MyInt.ToString() – Andrey

+0

@Andrey, buen punto, mi edición es un mejor ejemplo. –

0

El La razón por la que no puedo pensar es porque _myInt aparece en la parte superior del menú contextual de intellisense.

No creo que el acceso a _myInt viole el espíritu de encapsulación; es un campo de miembro privado de una clase. Cualquier código dentro de la clase DEBE usar el _miInt. 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 forma parte del contrato público.

Y como dije, es más fácil agarrar _myInt con intellisense cuando está codificando.

+0

Es más fácil agarrar CUALQUIER variable con intellisense mientras codifica. Si su convención de nomenclatura variable gira completamente alrededor de la ubicación de la variable en la lista intellisense, apostaría a que los símbolos no se nombrarán tan bien como podrían. –

16

Interesante pregunta.

Después de buscar 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 (ni debe haber) forma de recuperar una contraseña después de que se haya establecido.

2

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 generalmente estoy de acuerdo.

0

Estoy seguro de que la característica está allí simplemente para la simetría con una variable de solo obtener. Como Aphex algo implícitamente implica, algunas cosas no tienen sentido y solo están ahí porque es más fácil dejarlo que eliminarlo.

1

Cualquier información que debe fluir de una manera es útil a través de una propiedad de solo escritura. En general, escribimos clases para que fluya o salga la información. En el caso de solo escritura, debe pensar en situaciones en las que la información solo debe fluir hacia adentro y 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 alguien acceda a ella, obtenemos el patrón get/set común. 99.9% del tiempo así es como se usan las propiedades. Dado que hay otras maneras, igual de fáciles que pueden ser más robustas para lograr esto, se trata más de una construcción semántica que se dejó para la simetría que nada. Uno de los raros casos en que algo no fue sacado y el izquierdo con "¿Por qué demonios lo eliminaron?".

10

Uno de los usos para una propiedad de solo escritura es admitir la inyección de dependencia del colocador.

Digamos que tenía una clase:

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

El WhizbangProvider no está destinada a ser visitada por el mundo exterior. Nunca me gustaría interactuar con 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 enciende una exhibición de fuegos artificiales. O tal vez usted prefiere ver un espectáculo de luz y agua:

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

Y así sucesivamente ....

+1

+1 por ser un buen "contraejemplo", a pesar de que la justificación aún no resuena conmigo. :-) –

+1

Un caso de uso para la inyección del colocador está en las clases básicas. Si, en cambio, eligió la inyección de constructor, cualquier clase derivada debería escribir una sobrecarga de constructor. – neontapir

0

he tenido motivo para una propiedad de sólo escritura.

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

Soy un gran admirador de usar Ninject para la inyección de dependencias, usando la inyección de constructor para satisfacer todas las dependencias que una clase pueda tener. En su mayor parte, estas dependencias se declararían private readonly fieldName y se asignarían 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 cualquier mecanismo de fábrica que ASP.NET use para crear la instancia de clase para un servicio web depende de que haya un constructor sin argumentos, que anuló mi inyección de constructor.

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

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

Volviendo al punto de que los servicios inyectados son dependencias para la clase, en lugar de responsabilidades que tiene la clase, no quiero que otras clases accedan a estas propiedades de dependencias, así que marco la propiedad get como privada.