2010-11-22 17 views
27
class TestClass 
{ 
    private string _privateString = "hello"; 
    void ChangeData() 
    { 
     TestClass otherTestClass = new TestClass(); 
     otherTestClass._privateString = "world"; 
    } 
} 

Este código se compila en C# y el equivalente funciona en PHP, pero ¿alguien puede explicar el motivo por el cual otherTestClass._privateString se puede cambiar aquí?¿Por qué se puede cambiar la variable de miembro privado por instancia de clase?

Hubiera pensado que una instancia de una clase no debería poder cambiar una variable miembro privada bajo ninguna circunstancia, y que intentar acceder al otherTestClass._privateString daría un error de "inaccesible debido a nivel de protección".

Sin embargo, este no es el caso, entonces ¿por qué la creación de instancias de un objeto dentro de su propia clase le permite acceder a los miembros privados? Y si lo hiciera, ¿no rompe esto la encapsulación en cierta medida? ¿O me estoy perdiendo algo obvio?

  • (No estoy preguntando si el diseño de la clase anterior es una buena práctica, sólo me preguntaba acerca de la teoría detrás de él.)

Editar - Gracias por las respuestas y comentarios. Para aclarar, también me interesa saber si ser capaz de hacer esto se considera una característica positiva, o si es una compensación necesaria para una mejor verificación/claridad del código en tiempo de compilación/porque la mayoría de los otros lenguajes lo hacen de esa manera o lo que sea. Me parece ideal que el compilador lo prevenga o lo advierta, pero luego estoy lejos de ser un diseñador de lenguaje. Cualquier ejemplo de cómo es que de esta manera te permite hacer algo útil (sin violar la encapsulación) que de otra manera sería difícil o imposible, sería genial.

+0

BTW: Puede hacer 'ChangeData()' even 'static' y aún podrá acceder a miembros privados. – ulrichb

+0

@ulrichb - Es importante señalar para el OP que no puede usar la palabra clave 'this' para acceder a miembros privados si' ChangeData() 'es' static'. – TheCloudlessSky

+1

Como ejemplo de un idioma que es diferente: en Ruby, public es lo mismo, pero private significa "solo accesible por la misma instancia" y protected significa "solo accesible desde la misma clase". La herencia no tiene nada que ver con eso allí. – Tesserex

Respuesta

35

Los miembros privados son accesibles a cualquier código dentro del texto del programa de esa clase (incluso dentro de tipos anidados). No tiene nada que ver con qué instancia de la clase está tratando.

No creo que esto viole la encapsulación: la API aún está separada de la implementación, pero la implementación "sabe" sobre sí misma, independientemente de la instancia que esté viendo.

Creo que en otros idiomas este no es cómo funciona la accesibilidad, pero definitivamente es para C# y Java. (Java tiene reglas ligeramente diferentes sobre lo que puede acceder a los miembros privados, pero el código traducido para lo que ha escrito seguirá funcionando.)

+3

La implementación de la accesibilidad en el nivel de instancia requeriría un control en tiempo de ejecución para cada acceso de variable miembro, mientras que este modelo se puede verificar en tiempo de compilación. –

+1

@James: Bueno, no necesariamente.* Usted * podría * exigir que los miembros privados solo estuvieran disponibles a través de la referencia "this". Sería horrible, pero posible. –

+1

Agregaría a la respuesta de Jon que este tipo de control de acceso permite que los operadores n-arios como la igualdad se escriban fácilmente. Sería mucho más difícil implementar el operador de igualdad si ninguna instancia tuviera acceso a los otros miembros privados. –

9

Esto se debe a que C# impone la privacidad a nivel de clase y no la privacidad a nivel de objeto.

La mayoría de los lenguajes principales imponen la misma política, es decir, C#, C++ y Java. Creo que la razón es:

1) porque los desarrolladores están acostumbrados a ese tipo de política;

2) porque la privacidad a nivel de objeto se volvería demasiado tediosa a cambio de muy pocas ventajas.

+0

No creo que hubiera Debe ser necesario utilizar "esto", ya que los compiladores sí pueden distinguir las variables de los miembros. Creo que sería tedioso tener métodos getter para el valor de miembro de cada clase, por ejemplo. De hecho, iría en contra de la encapsulación porque ¡también estarías exponiendo miembros privados a otra clase! – Simone

+0

@ miket2e Intenta implementar un constructor de copia o una función Equals simple con privacidad a nivel de objeto. Eso simple en el C# actual: devuelve this._somePrivateField.Eq uals (other._somePrivateField) - si puede acceder a other._somePrivateField, ¿cómo implementaría dicha función sin agregar getters públicos? –

+1

@MichaelStum: Una ventaja de tener campos sea instancia privada o instancia protegida es que hacerlo así deja en claro que las clases derivadas pueden rediseñar esos campos sin violar el Principio de sustitución Liskov. De lo contrario, dicho cambio de propósito puede causar violaciones de LSP. Algo como 'Equals' se puede implementar teniendo un método 'privado' de clase privada que acepte el contenido del otro objeto (ya sea como un conjunto de parámetros discretos, o usando un tipo protegido por clase), y teniendo el público' Igual 'El método de un objeto pasa su estado al método 'Protegido' es igual al otro. – supercat

Cuestiones relacionadas