¿Hay alguna razón para usar propiedades privadas en C #?

Me acabo de dar cuenta de que la construcción de la propiedad C # también se puede usar con un modificador de acceso privado :

private string Password { get; set; } 

Aunque esto es técnicamente interesante, no puedo imaginar cuándo lo usaría, ya que un campo privado implica aún menos ceremonias :

 private string _password; 

y no me puedo imaginar cuándo necesitaría ser capaz de obtener internamente pero no establecer o establecer, pero no obtener un campo privado:

 private string Password { get; } 

o

 private string Password { set; } 

pero tal vez haya un caso de uso con clases anidadas / heredadas o tal vez donde un get / set contenga lógica en lugar de simplemente devolver el valor de la propiedad, aunque tendería a mantener las propiedades estrictamente simples y permitir que los métodos explícitos hagan cualquier lógica. por ejemplo, GetEncodedPassword() .

¿Alguien usa propiedades privadas en C # por algún motivo o es solo uno de esos constructos técnicamente posibles pero rara vez utilizados en el código real?

Apéndice

Buenas respuestas, leyendo a través de ellas seleccioné estos usos para propiedades privadas:

  • cuando los campos privados necesitan ser cargados de forma perezosa
  • cuando los campos privados necesitan lógica adicional o son valores calculados
  • ya que los campos privados pueden ser difíciles de depurar
  • para “presentarte un contrato”
  • para convertir / simplificar internamente una propiedad expuesta como parte de la serialización
  • envolviendo variables globales para ser usadas dentro de su clase

Los uso si necesito guardar un valor en caché y quiero cargarlo de forma perezosa.

 private string _password; private string Password { get { if (_password == null) { _password = CallExpensiveOperation(); } return _password; } } 

El uso principal de esto en mi código es la inicialización lenta, como han mencionado otros.

Otra razón para las propiedades privadas sobre los campos es que las propiedades privadas son mucho más fáciles de depurar que los campos privados. Frecuentemente quiero saber cosas como “este campo se está configurando inesperadamente, ¿quién es el primer interlocutor que establece este campo?” y es mucho más fácil si puedes poner un punto de interrupción en el setter y presionar “ir”. Puedes poner logging allí. Puedes poner métricas de rendimiento allí. Puede colocar comprobaciones de coherencia que se ejecutan en la comstackción de depuración.

Básicamente, todo se reduce a: el código es mucho más poderoso que los datos . Cualquier técnica que me permita escribir el código que necesito es buena. Los campos no le permiten escribir código en ellos, las propiedades sí.

tal vez haya un caso de uso con clases anidadas / heredadas o tal vez donde un get / set pueda contener lógica en lugar de solo devolver el valor de la propiedad

Personalmente uso esto incluso cuando no necesito lógica en el getter o setter de una propiedad. El uso de una propiedad, incluso una privada, ayuda a proteger su código a futuro para que pueda agregar la lógica a un getter más tarde, si es necesario.

Si considero que una propiedad puede requerir una lógica adicional, a veces la incluiré en una propiedad privada en lugar de usar un campo, para no tener que cambiar el código más adelante.


En un caso semi relacionado (aunque es diferente de su pregunta), con mucha frecuencia uso los organismos privados en las propiedades públicas:

 public string Password { get; private set; } 

Esto le proporciona un getter público, pero mantiene al setter en privado.

La inicialización lenta es un lugar donde pueden ser prolijos, por ejemplo

 private Lazy mytype = new Lazy(/* expensive factory function */); private MyType MyType { get { return this.mytype.Value; } } // In C#6, you replace the last line with: private MyType MyType => myType.Value; 

Entonces puede escribir: this.MyType todas partes en lugar de this.mytype.Value y encapsular el hecho de que se ejemplifica perezosamente en un solo lugar.

Una cosa que es una pena es que C # no admite el scope del campo de respaldo de la propiedad (es decir, declararlo dentro de la definición de propiedad) para ocultarlo por completo y garantizar que solo se pueda acceder a él a través de la propiedad.

Un buen uso para las propiedades de obtención privada solo son los valores calculados. Varias veces he tenido propiedades que son de solo lectura y solo hago un cálculo sobre otros campos en mi tipo. No es digno de un método y no es interesante para otras clases, por lo que es propiedad privada.

El único uso que puedo pensar

 private bool IsPasswordSet { get { return !String.IsNullOrEmpty(_password); } } 

Las propiedades y los campos no son uno a uno. Una propiedad se trata de la interfaz de una clase (ya sea que se trate de su interfaz pública o interna), mientras que un campo trata acerca de la implementación de la clase. Las propiedades no deben verse como una forma de exponer los campos, sino como una forma de exponer la intención y el propósito de la clase.

Al igual que usa propiedades para presentar un contrato a sus consumidores sobre lo que constituye su clase, también puede presentar un contrato para usted por motivos muy similares. Entonces sí, uso propiedades privadas cuando tiene sentido. A veces, una propiedad privada puede ocultar detalles de implementación como la carga diferida, el hecho de que una propiedad es realmente un conglomerado de varios campos y aspectos, o que una propiedad necesita ser instanciada virtualmente con cada llamada (piense DateTime.Now ). Definitivamente hay momentos en los que tiene sentido hacer cumplir esto, incluso en ti mismo en el back-end de la clase.

Los uso en serialización, con cosas como DataContractSerializer o protobuf-net que admiten este uso ( XmlSerializer no). Es útil si necesita simplificar un objeto como parte de la serialización:

 public SomeComplexType SomeProp { get;set;} [DataMember(Order=1)] private int SomePropProxy { get { return SomeProp.ToInt32(); } set { SomeProp = SomeComplexType.FromInt32(value); } } 

Una cosa que hago todo el tiempo es almacenar las variables / caché “globales” en HttpContext.Current

 private static string SomeValue{ get{ if(HttpContext.Current.Items["MyClass:SomeValue"]==null){ HttpContext.Current.Items["MyClass:SomeValue"]=""; } return HttpContext.Current.Items["MyClass:SomeValue"]; } set{ HttpContext.Current.Items["MyClass:SomeValue"]=value; } } 

Los uso de vez en cuando. Pueden facilitar la depuración de las cosas cuando puede colocar fácilmente un punto de interrupción en la propiedad o puede agregar una statement de registro, etc.

También puede ser útil si luego necesita cambiar el tipo de sus datos de alguna manera o si necesita usar el reflection.

Utilizo propiedades privadas para reducir el código para acceder a las propiedades secundarias que a menudo usar.

  private double MonitorResolution { get { return this.Computer.Accesories.Monitor.Settings.Resolution; } } 

Es útil si hay muchas sub propiedades.

Es una práctica común modificar miembros con métodos get / set, incluso privados. Ahora, la lógica detrás de esto es que usted sepa que su get / set siempre se comporta de una manera particular (por ejemplo, desencadenando eventos) lo que no parece tener sentido ya que estos no se incluirán en el esquema de propiedad … pero los viejos hábitos se mueren duro.

Tiene mucho sentido cuando hay una lógica asociada con el conjunto de propiedades o get (creo que la inicialización es lenta) y la propiedad se usa en algunos lugares de la clase.

Si es solo un campo de respaldo recto? Nada viene a la mente como una buena razón.

Bueno, como nadie mencionó, puedes usarlo para validar datos o para bloquear variables.

  • Validación

     string _password; string Password { get { return _password; } set { // Validation logic. if (value.Length < 8) { throw new Exception("Password too short!"); } _password = value; } } 
  • Cierre

     object _lock = new object(); object _lockedReference; object LockedReference { get { lock (_lock) { return _lockedReference; } } set { lock (_lock) { _lockedReference = value; } } } 

    Nota: Al bloquear una referencia, no bloquea el acceso a los miembros del objeto al que se hace referencia.

Referencia diferida: cuando la carga es lenta, es posible que tengas que hacerlo asincrónico, por lo que actualmente hay AsyncLazy . Si utiliza versiones anteriores a Visual Studio SDK 2015 o no las usa, también puede usar AsyncLazy de AsyncEx .