Campos públicos versus propiedades automáticas

353

A menudo se nos dice que debemos proteger la encapsulación haciendo métodos getter y setter (propiedades en C #) para los campos de clase, en lugar de exponer los campos al mundo exterior.

Pero hay muchas ocasiones en que un campo está ahí para contener un valor y no requiere ningún cálculo para obtener o establecer. Para estos todos haríamos este número:

public class Book
{
    private string _title;

    public string Title
    {
          get{ return _title;  }
          set{ _title = value; }
    }
}

Bueno, tengo una confesión, no podía soportar escribir todo eso (realmente, no era tener que escribirlo, era tener que mirarlo), así que me volví pícaro y utilicé los campos públicos.

Luego viene C # 3.0 y veo que agregaron propiedades automáticas:

public class Book
{
    public string Title {get; set;} 
}

lo cual es más ordenado, y estoy agradecido por ello, pero en realidad, ¿qué es tan diferente a solo hacer un campo público?

public class Book
{
    public string Title;
}
IJ Kennedy
fuente
posible duplicado de la diferencia entre propiedad y campo en C # .NET
3.5+
66
He convertido un feild en una propiedad solo para poder establecer un punto de interrupción en el setter
Ian Ringrose
1
Tiendo a convertir cualquier cosa que no sea privada en una propiedad porque darme cuenta de que debo refactorizar un campo en una propiedad me ha generado un dolor de cabeza innecesario. Propiedades, campos y métodos. ¡Oh mi! llama a una incompatibilidad que me ha mordido en el pasado.
Steven Wexler
2
El propfragmento de código agiliza la creación de propiedades. Simplemente escriba la proppestaña.
Tono Nam

Respuestas:

175

En una pregunta relacionada que tuve hace algún tiempo, había un enlace a una publicación en el blog de Jeff, explicando algunas diferencias.

Propiedades frente a variables públicas

  • La reflexión funciona de manera diferente en las variables frente a las propiedades, por lo que si confía en la reflexión, es más fácil usar todas las propiedades.
  • No puede enlazar datos con una variable.
  • Cambiar una variable a una propiedad es un cambio radical. Por ejemplo:

    TryGetTitle(out book.Title); // requires a variable
Michael Stum
fuente
24
"Cambiar una variable a una propiedad es un cambio radical". Esto, por supuesto, solo se aplica al escribir una biblioteca reutilizable, que la mayoría de los desarrolladores no están haciendo.
Steven
30
Además, las propiedades, incluso las propiedades automáticas, pueden ser virtuales, donde los campos no pueden. Por lo tanto, una clase base puede tener una implementación de campo de respaldo simple producida por el compilador para un auto-prop, mientras que las clases derivadas pueden realizar validaciones adicionales u otras lógicas / cálculos.
KeithS
28
Además, un campo es una variable y se puede pasar por referencia ( refo outpalabra clave), mientras que una propiedad es un par de accesores y no se puede pasar por referencia. Por ejemplo, bool success = TryGetMyTitle(out myBook.Title);qué usos outfuncionarán con un campo y no con una propiedad. ¡Este es un claro ejemplo de por qué el cambio de campo a propiedad es un cambio radical!
Jeppe Stig Nielsen
2
@KyleBaran No, no tiene mucho sentido porque una propiedad es un par de métodos de acceso, no una variable. Lo habitual es declarar una variable local (posiblemente leer la propiedad y poner su valor en la variable local), pasar la variable local como ref/ outy luego establecer la propiedad en el valor que la variable local tiene. Pero luego, el método llamado no accede a la propiedad, accede a la variable local que creó allí.
Jeppe Stig Nielsen
55
@theberserker Es cierto, aunque en C # 6 puede hacer public int Foo { get; }lo que creará una propiedad automática con un campo de respaldo de solo lectura.
Michael Stum
83

Ignorando los problemas de API, lo que encuentro más valioso sobre el uso de una propiedad es la depuración.

El depurador CLR no admite puntos de ruptura de datos (la mayoría de los depuradores nativos sí lo hacen). Por lo tanto, no es posible establecer un punto de interrupción en la lectura o escritura de un campo en particular en una clase. Esto es muy limitante en ciertos escenarios de depuración.

Debido a que las propiedades se implementan como métodos muy delgados, es posible establecer puntos de interrupción en la lectura y escritura de sus valores. Esto les da una gran ventaja sobre los campos.

JaredPar
fuente
2
Diez años más tarde, los puntos de corte de datos están aquí, al menos para .NET Core :)
Luaan
72

El cambio de un campo a una propiedad rompe el contrato (por ejemplo, requiere que se vuelva a compilar todo el código de referencia). Entonces, cuando tiene un punto de interacción con otras clases, cualquier miembro público (y generalmente protegido), desea planificar el crecimiento futuro. Hazlo siempre usando propiedades.

Hoy en día, no es nada para que sea una propiedad automática, y 3 meses después se dan cuenta de que desea hacerlo con carga perezosa y ponen un cheque nulo en el getter. Si ha utilizado un campo, este es un cambio de compilación en el mejor de los casos e imposible en el peor, dependiendo de quién y qué más depende de sus ensamblajes.

Rex M
fuente
99
Me gustó esta respuesta porque no usa las palabras 'reflexión', 'interfaz' o 'anulación'. (muy mal por el 'contrato')
65

Solo porque nadie lo mencionó: no se pueden definir campos en las interfaces. Entonces, si tiene que implementar una interfaz específica que defina propiedades, las propiedades automáticas a veces son una característica realmente agradable.

MartinStettner
fuente
1
Diría que si necesita una interfaz que defina propiedades, debería ser una clase abstracta. El hecho de que c # le permita definir propiedades en las interfaces, no significa que deba usarlas. Es un mal diseño.
Odys
8
@odyodyodys - No estoy seguro de estar de acuerdo en que este es un mal diseño. Por favor explique su razonamiento?
Zaid Masud
44
@odyodyodys Estoy de acuerdo con zooone9243: Imp, desde el punto de vista del diseño, no hay diferencia entre declarar una propiedad y declarar un par getter / setter (que es una práctica común para las interfaces).
MartinStettner
22
@ zooone9243, + MartinStettner: Eso fue hace 6 meses, aprendí mucho desde entonces. Lo estoy recuperando :)
Odys
47

Una gran diferencia que a menudo se pasa por alto y no se menciona en ninguna otra respuesta: anulación . Puede declarar propiedades virtuales y anularlas, mientras que no puede hacer lo mismo para los campos de miembros públicos.

Zaid Masud
fuente
10

Se trata de versiones y estabilidad de API. No hay diferencia, en la versión 1, pero más tarde, si decide que necesita convertir esto en una propiedad con algún tipo de verificación de errores en la versión 2, no tiene que cambiar su API, no hay cambios de código, en ningún otro lugar que no sea La definición de la propiedad.

Reed Copsey
fuente
10

Otra ventaja de las propiedades implementadas automáticamente sobre los campos públicos es que puede hacer que los accesos de conjunto sean privados o protegidos, proporcionando a la clase de objetos donde se definió un mejor control que el de los campos públicos.

Arnaldo
fuente
8

No hay nada malo en hacer un campo public. Pero recuerde que crear getter/settercon privatecampos no es encapsulación. OMI, si no te interesan otras características de a Property, también podrías hacerlo public.

fastcodejava
fuente
1

Si luego decide verificar que el título es único, al compararlo con una colección o una base de datos, puede hacerlo en la propiedad sin cambiar ningún código que dependa de él.

Si elige solo un atributo público, tendrá menos flexibilidad.

La flexibilidad adicional sin romper el contrato es lo más importante para mí sobre el uso de propiedades y, hasta que realmente necesite la flexibilidad, la generación automática tiene más sentido.

James Black
fuente
0

Una cosa que encuentro muy útil, así como todo el código y las razones de prueba, es que si se trata de una propiedad frente a un campo, el IDE de Visual Studio le muestra las referencias de una propiedad pero no de un campo.

TrtlBoy
fuente
0

Mi punto de vista después hizo algunas investigaciones

  1. Validación.
  2. Permitir reemplazar el descriptor de acceso para cambiar el comportamiento de una propiedad.
  3. Propósito de depuración. Podremos saber cuándo y qué cambia la propiedad estableciendo un punto de interrupción en el descriptor de acceso.
  4. Podemos tener un campo solo establecido. Por ejemplo, public set () y private get (). Esto no es posible con el campo público.

Realmente nos da más posibilidades y extensibilidad.

KunYu Tsai
fuente