c# remarks ¿Cuándo tiene sentido utilizar un campo público?




remarks c# (8)

Así que la mejor respuesta que puedo dar es que cuando haces magia a través de la reflexión, como se suele hacer cuando se aprovecha un lenguaje estático, las propiedades tienen un significado sobre los campos. Desde elementos como las herramientas de ORM, los mapeadores y los datos de enlace, las propiedades pueden tener un significado diferente al de los campos desde ese punto de vista de comportamiento.

El JITter no convierte las propiedades en campos, puede alinearlas, aunque no prometo que lo haga en todos los casos.

Esta es una pregunta que he tenido desde hace un tiempo:

¿Cuándo tiene sentido exponer públicamente un campo así?

public class SomeClass()
{
   public int backing;
}

La desventaja de hacer esto (además de enfurecer a los elitistas de POO) es que tiene que introducir un cambio de ruptura en su API si alguna vez necesita agregar alguna lógica a estos datos. Supongo que de eso se tratan los elitistas.

La mejor práctica en Java y C # ha sido durante mucho tiempo usar los métodos de obtención / configuración o propiedades para acceder a los campos.

public class SomeClass()
{
   private int backing;

   public int getBacking()
   {
      return backing;
   }

   public void setBacking(int v)
   {
      backing = v;
   }
}

C # ha evolucionado esto a una sintaxis bastante simple con propiedades automáticas:

public class SomeClass()
{
   public int Backing { get; set; }
}

Lazy me sigue sintiendo que esto es demasiado largo ya que es algo que me encuentro haciendo mucho. Más importante aún, no estoy seguro de saber dónde tendría más sentido un campo público.

¿Por qué no tratar los campos declarados públicamente como propiedades (o métodos) detrás de escena? De esa manera sería imposible enojar a los dioses y disociarlos un poco menos.

public class SomeClass()
{
   public int backing;   // The same as public int backing { get; set; }
}

Para una propiedad que no hace nada más que envolver el campo subyacente, estoy bastante seguro de que el JIT optimiza las llamadas al método, por lo que el rendimiento probablemente no sea el problema. ¿Alguna idea? (aparte de la convención de caso adecuada para el nombre de campo)

EDIT: Gracias por todas las respuestas. Siento que tal vez no todos están entendiendo mi pregunta. ¿Cuándo sería un campo público una mejor opción que una propiedad? ¿Por qué es una mejor opción? Si la única razón es la conveniencia (menos la escritura y el desorden), entonces, ¿cuál sería el inconveniente de que el compilador genere una propiedad "debajo del capó" cuando se encuentre un campo público? Básicamente, sería imposible crear un verdadero campo público (porque todos serían propiedades). ¿Qué estaría mal con eso? Gracias.


¿Cuándo tiene sentido exponer un campo públicamente?

Entre otros lugares, en clases privadas como a continuación.

public class MyOuterClass
{
      private class MyInnerClass
      {
            public int val ; // why bother w/boiler plate
      }
}

Aquí está el resumen de las ventajas y desventajas de los campos públicos:

Ventajas

  • Menos desorden en el código
  • Mejor rendimiento (en algunos casos)

Desventajas

  • La representación no se puede cambiar sin cambiar la API
  • No se pueden imponer invariantes (a menos que el campo sea inmutable)
  • No se pueden realizar acciones adicionales al acceder a estos campos

Entonces, ¿cuándo debemos usar campos públicos? Depende. Es obvio que para las clases públicas las desventajas superan las ventajas. Los posibles problemas con la evolución del código dentro del paquete son mucho peores que más desorden en el código y menor impacto en el rendimiento.

Sin embargo, una clase puede ser un paquete privado o incluso anidado privado, en cuyo caso se localizarán los cambios probables en el código. Por lo tanto, es absolutamente posible utilizar campos públicos. También hay casos en que la diferencia de rendimiento no es tan pequeña. Por ejemplo, la guía de desarrolladores de Android afirma que es una buena práctica utilizar el acceso directo a los campos en lugar de los que los obtienen / configuran, donde es posible porque es varias veces más rápido.

Para resumir, citaré uno de mis libros favoritos, Effective Java by J. Bloch, artículo 14:

En resumen, las clases públicas nunca deben exponer campos mutables. Es menos perjudicial, aunque todavía cuestionable, que las clases públicas expongan campos inmutables. Sin embargo, a veces es deseable que las clases anidadas privadas o de paquete expongan campos, ya sean mutables o inmutables.


Creo que tiene sentido cuando quieres agrupar algunas variables / objetos (algo así como una struct C). Por ejemplo:

class Pixel {
  public int x;
  public int y;
  Color c;
  // Other Pixel related information
}

Como no hay métodos, nada se rompe si se usa un valor incorrecto y combina muy bien estas variables.


Un escenario, al menos en .NET, es la interoperabilidad con las API de C. A menudo, declarará las versiones C # o VB de las estructuras de la API de Windows, y es común usar campos públicos para estas porque la razón normal para hacer que los campos sean privados, para evitar que alguien juegue con ellos detrás de su espalda, fracasa. En este caso, usted sabe que algo cambiará los campos detrás de su espalda, ¡ese es el propósito de tener la estructura!

Por supuesto, por lo general, no expondrá esas estructuras no encapsuladas al código de la aplicación; las tratará como elementos privados del módulo P / Invoke, por lo que el código de la aplicación todavía no se ocupará de los campos públicos.


La mejor práctica en Java y C # ha sido durante mucho tiempo usar los métodos de obtención / configuración o propiedades para acceder a los campos.

Creo que ese es el primer problema: la idea de que si tienes un captador también debes tener un setter. Esto es un error; en muchos casos, un definidor no es necesario porque no hay una necesidad real de modificar el valor del atributo de un objeto, y eliminar la posibilidad simplifica la clase.

Los casos extremos es no tener mutadores en absoluto. La etapa final para hacer que la clase sea inmutable nunca es hacer que los valores de campo mutables (recuerde, Java final no es como C ++ const ) directamente accesible. Y las clases de pequeño valor deberían ser inmutables. Solo un método de obtención puede proporcionar acceso seguro a campos potencialmente mutables, mediante la creación de una copia (en C ++, simplemente tiene una obtención que devuelve por valor). Podría prescindir del getter para aquellos campos que no requieren copia defensiva, pero algunos campos de una clase pueden requerir un getter y otros no. Pero eso sería confuso,


En los proyectos con una complejidad no trivial, rara vez, pero a veces, es una buena idea utilizar campos públicos. Un ejemplo que viene a la mente:

/** 
 * A two-dimensional mathematical vector. Immutable so instances may be freely shared
 * without violating encapsulation.
 */
public class Vec2 {
    public final int x, y;

    // bunch of constructors and methods omitted
}

Justificación: es extremadamente improbable que la representación interna deba cambiarse o que se realice cualquier tipo de operación al leer x o y . Es decir, usar un setter no confiere ningún beneficio aquí.

Sin embargo conferiría algunos costos:

  1. El campo final público dejará en claro que la clase es inmutable, con un captador, debes confiar en el comentario de la documentación. (Tenga en cuenta que la ausencia de un setter no implica inmutabilidad, ya que algún otro método podría asignar el campo)
  2. El código que accede al vector sería un poco menos legible, ya que get () no confiere información semántica significativa, pero aún debe omitirse al leer el código (al menos en Java, C # es mejor aquí).
  3. Este es un uso frecuente de clase de nivel extremadamente bajo, y la sobrecarga de invocación puede convertirse en un problema. Sí, la máquina virtual puede realizar inlineado en muchos casos, pero al menos para los métodos no finales, es probable que se mantenga cierta sobrecarga incluso si no hay subclases cargadas actualmente.

Uno de los escenarios en los que el campo público es una mejor opción es proporcionar constantes de su clase.

Por ejemplo, ver:

public const double PI

definido en System.Math.

Este enfoque se ve favorecido porque informa explícitamente a los consumidores de su clase, que este miembro no incluye ninguna lógica, validación ni ninguna otra operación relacionada con el estado, por lo que puede usarse en el contexto que desee.

El otro en el que puedo pensar es cuando necesita clases como contenedores para operaciones simples (o simplemente para pasar la gran cantidad de parámetros a un método), como ejemplo, vea System.Windows.Point . En la mayoría de los casos, estos contenedores están modelados como estructuras sin embargo.







design-patterns