Implementadores y getters auto-implementados vs. campos públicos

Veo una gran cantidad de código de ejemplo para las clases C # que hace esto:

public class Point { public int x { get; set; } public int y { get; set; } } 

O, en código anterior, lo mismo con un valor de respaldo privado explícito y sin las nuevas propiedades implementadas automáticamente:

 public class Point { private int _x; private int _y; public int x { get { return _x; } set { _x = value; } } public int y { get { return _y; } set { _y = value; } } } 

Mi pregunta es por qué. ¿Hay alguna diferencia funcional entre hacer lo anterior y simplemente hacer que estos miembros sean campos públicos, como a continuación?

 public class Point { public int x; public int y; } 

Para ser claros, entiendo el valor de los getters y setters cuando necesitas hacer alguna traducción de los datos subyacentes. Pero en los casos en que solo pasa los valores, parece innecesariamente detallado.

Tiendo a estar de acuerdo (que parece innecesariamente prolijo), aunque este ha sido un problema que nuestro equipo todavía no ha resuelto y por eso nuestros estándares de encoding todavía insisten en propiedades detalladas para todas las clases.

Jeff Atwood se ocupó de esto hace unos años. El punto más importante que observó retrospectivamente es que cambiar de un campo a una propiedad es un cambio radical en su código; cualquier cosa que lo consum debe ser recomstackdo para funcionar con la nueva interfaz de clase, por lo que si algo que esté fuera de su control consume su clase, es posible que tenga problemas.

También es mucho más simple cambiarlo a esto más tarde:

 public int x { get; private set; } 

Encapsula la configuración y el acceso de esos miembros. Si en algún momento a partir de ahora un desarrollador del código necesita cambiar la lógica cuando se accede a un miembro o se establece, se puede hacer sin cambiar el contrato de la clase.

La idea es que incluso si la estructura de datos subyacente necesita cambiar, la interfaz pública para la clase no tendrá que cambiarse.

C # puede tratar propiedades y variables de manera diferente a veces. Por ejemplo, no puede pasar propiedades como parámetros ref o out . Entonces, si necesita cambiar la estructura de datos por alguna razón y estaba usando variables públicas y ahora necesita usar propiedades, su interfaz tendrá que cambiar y ahora el código que accede a la propiedad x puede no comstackrse más como lo hizo cuando era variable X:

 Point pt = new Point(); if(Int32.TryParse(userInput, out pt.x)) { Console.WriteLine("x = {0}", pt.x); Console.WriteLine("x must be a public variable! Otherwise, this won't compile."); } 

El uso de propiedades desde el principio evita esto, y puede tener la libertad de ajustar la implementación subyacente todo lo que necesite sin romper el código del cliente.

Setter y Getter le permiten agregar capas de abstracción adicionales y en OOP puro, siempre debe acceder a los objetos a través de la interfaz que están proporcionando al mundo exterior …

Considere este código, que lo guardará en asp.net y que no sería posible sin el nivel de abstracción proporcionado por los incubadores y getters:

 class SomeControl { private string _SomeProperty ; public string SomeProperty { if ( _SomeProperty == null ) return (string)Session [ "SomeProperty" ] ; else return _SomeProperty ; } } 

Desde getters implementados automáticamente toma el mismo nombre para la propiedad y las variables de almacenamiento privadas reales. ¿Cómo puedes cambiarlo en el futuro? Creo que el punto que se dice es que use el campo implementado automáticamente en lugar de para que pueda cambiarlo en el futuro si en caso de que necesite agregar lógica a getter y setter.

Por ejemplo:

 public string x { get; set; } 

y, por ejemplo, ya usa xa muchas veces y no quiere romper su código.

¿Cómo se cambia el setter de obtención automática … por ejemplo, para setter solo se permite establecer un formato de número de teléfono válido … ¿cómo se cambia el código para que solo se cambie la clase?

Mi idea es agregar una nueva variable privada y agregar el mismo x getter y setter.

 private string _x; public string x { get {return x}; set { if (Datetime.TryParse(value)) { _x = value; } }; } 

¿Es esto lo que quieres decir al hacerlo flexible?

También debe tenerse en cuenta el efecto del cambio en los miembros públicos en lo que respecta al enlace y la serialización. Ambos a menudo dependen de propiedades públicas para recuperar y establecer valores.

Además, puede poner puntos de corte en getters y setters, pero no puede en los campos.

AFAIK la interfaz CIL generada es diferente. Si cambia un miembro público a una propiedad, está cambiando su interfaz pública y necesita reconstruir cada archivo que use esa clase. Esto no es necesario si solo cambia la implementación de getters y setters.

Tal vez hacer públicos los campos que puedas te lleve a un Modelo de dominio más anémico .

Saludos cordiales

También vale la pena señalar que no puede hacer Auto Properties Readonly y no puede inicializarlas en línea. Ambas cosas son las que me gustaría ver en una versión futura de .NET, pero creo que no puedes hacer ninguna de ellas en .NET 4.0.

Las únicas veces que utilizo un campo de respaldo con propiedades en estos días es cuando mi clase implementa INotifyPropertyChanged y necesito activar el evento OnPropertyChanged cuando se cambia una propiedad.

También en estas situaciones, establezco los campos de respaldo directamente cuando los valores se pasan desde un constructor (no es necesario intentar disparar el OnPropertyChangedEvent (que sería NULL en este momento), en cualquier otro lugar que use la propiedad en sí.

Nunca se sabe si es posible que no necesite alguna traducción de los datos más adelante. Estás preparado para eso si escondes a tus miembros. Los usuarios de su clase no notarán si agrega la traducción ya que la interfaz sigue siendo la misma.

La mayor diferencia es que, si alguna vez cambias tu estructura interna, puedes mantener los getters y setters como están, cambiando su lógica interna sin dañar a los usuarios de tu API.

Si tiene que cambiar la forma en que obtiene xey en este caso, puede agregar las propiedades más adelante. Esto es lo que encuentro más confuso. Si usa variables de miembro público, puede cambiarlo fácilmente a una propiedad más adelante y usar variables privadas llamadas _x y _y si necesita almacenar el valor internamente.

Setters y getters son malos en principio (son un mal olor de OO – no voy a decir que son un antipatrón porque a veces son necesarios).

No, técnicamente no hay diferencia y cuando realmente quiero compartir el acceso a un objeto en estos días, de vez en cuando lo hago público final en lugar de agregar un getter.

La forma en que los setters y getters se “vendieron” es que es posible que necesites saber que alguien está obteniendo un valor o cambiando uno, lo que solo tiene sentido con los primitivos.

Los objetos de bolsa de propiedades como DAO, DTO y objetos de visualización se excluyen de esta regla porque estos no son objetos con un significado real de “OO Design” de la palabra Object. (No piensas en “pasar mensajes” a un DAO, es simplemente un montón de pares de atributos / valores).