La encapsulación significa que el estado de un objeto solo ocurre a través de una interfaz definida, y debido a esto, la clase puede asegurarse de que este estado sea siempre válido y de acuerdo con el propósito de la clase.
En algunos casos, por lo tanto, está perfectamente de acuerdo con el principio de encapsulación simplemente exponer un campo públicamente: todos los valores posibles para el campo son válidos con todos los demás valores posibles de todos los demás campos y, por lo tanto, el programador puede decidir activamente permitir el campo para ser manipulado libremente por código externo.
Sin embargo, estos casos están restringidos principalmente a clases que son en su mayoría "datos antiguos sin formato". Tampoco son muy interesantes en este sentido, así que basta de ellos.
En otros casos, en otros lenguajes, se tendría un método getter y setter, algo así como int getId()obtener un valor y void setId(int val)actualizarlo.
Las propiedades nos permiten usar la misma sintaxis para leer y escribir a través de métodos que usaríamos para leer y escribir un campo. Este es un buen azúcar sintáctico, aunque no vital.
(En realidad, debido a la forma en que funciona la reflexión y casos como DataBinder.Evaléste, puede ser útil tener una propiedad incluso cuando un campo funcionaría bien, pero eso es otro asunto).
Hasta que se introduzcan los setters privados (en realidad, lo que cambió con C # 2 es la sintaxis para tener un setter privado y un getter público o protegido en el mismo bloque), podríamos tener un método privado para hacer el trabajo del setter privado, entonces los setters privados no son realmente necesarios. Sin embargo, son útiles, por lo que aunque solo son azúcar sintáctico, son bastante útiles.
La encapsulación no es una cuestión de si sus establecedores (o captadores) son públicos, privados, protegidos o internos, sino una cuestión de si son apropiados . Comience con un valor predeterminado de que cada campo sea privado (y para el caso readonly) y luego, según sea necesario, agregue miembros (ya sean propiedades o métodos) que modifiquen esos campos y asegúrese de que el objeto siga siendo válido a medida que cambien . Esto asegura que se mantenga el invariante de una clase , lo que significa que las reglas que describen el conjunto válido de estados en los que puede estar nunca se rompen (los constructores también ayudan al asegurarse de que comience en un estado válido).
En cuanto a su última pregunta, a ser medios inmutables que una clase no tiene público, protegido o fijadores internos y sin público, protegido o métodos internos que cambian todos los campos. Hay grados de esto, en C # hay tres grados posibles:
Todos los campos de instancia de una clase son readonly, por lo tanto, incluso el código privado no puede alterarlo. Se garantiza que es inmutable (cualquier cosa que intente cambiarlo no se compilará) y posiblemente se pueden realizar optimizaciones en la parte posterior de esto.
Una clase es inmutable desde el exterior porque ningún miembro público cambia nada, pero el uso de no garantiza readonlyque no se cambie desde el interior.
Una clase es inmutable como se ve desde el exterior, aunque algún estado cambia como detalle de implementación. Por ejemplo, un campo podría memorizarse y, por lo tanto, mientras que desde el exterior un intento de obtenerlo simplemente recupera el mismo valor, el primer intento de este tipo realmente lo calcula y luego lo almacena para su recuperación en intentos posteriores.
private File settingsFile = null;y luego en uno de los constructores:if (settingsFile == null) { settingsFile = GetSettingsFile() };. Refactorizar código como ese me hizo llorar a veces :). El hecho de que pueda establecer un miembro antes del constructor no significa que deba hacerlo, ya que, con varios constructores, esto hace que sea DIFÍCIL seguir la lógica. Los establecedores privados te obligan a establecer valores dentro del constructor o más tarde.