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

Ten kod kompiluje się w języku C#, a odpowiednik działa w PHP, ale czy ktoś może wyjaśnić, dlaczego tutaj można zmienić otherTestClass._privateString?Dlaczego prywatne zmienne członkowskie mogą być zmieniane przez instancję klasy?

Wydaje mi się, że wystąpienie klasy nie powinno być w stanie zmienić prywatnej zmiennej członkowskiej w żadnych okolicznościach, a próba uzyskania dostępu do otherTestClass._privateString spowodowałaby błąd "niedostępny z powodu poziomu ochrony".

To nie jest przypadek, choć, więc dlaczego instancji obiektu wewnątrz własnej klasy pozwalają uzyskać dostęp do prywatnych członków? A czy w takim razie nie może to zepsuć enkapsulacji? Czy może brakuje mi czegoś oczywistego?

  • (Nie pytam, czy powyższe klasy konstrukcja jest dobra praktyka, po prostu zastanawiasz się o teorii za nim.)

Edycja - dzięki za odpowiedzi i komentarze. Aby wyjaśnić, jestem również zainteresowany wiedząc, czy możliwość to zrobić jest uważana za pozytywną cechę, lub jeśli jest to koniecznym kompromisem dla lepszego sprawdzania kompilacji/klarowności/ponieważ większość innych języków robi to w ten czy w inny sposób. Wydaje mi się, że idealnie kompilator zapobiegnie lub ostrzeże cię o tym, ale jestem daleki od projektanta języka. Wszelkie przykłady tego, jak to jest w ten sposób, pozwalają zrobić coś użytecznego (bez naruszania hermetyzacji), które w przeciwnym razie byłoby trudne lub niemożliwe, byłoby wspaniałe.

+0

BTW: Możesz zrobić 'ChangeData()' even 'static' i nadal będziesz mieć dostęp do prywatnych członków. – ulrichb

+0

@ulrichb - Ważne, aby zwrócić uwagę na OP, że nie można użyć słowa kluczowego 'this', aby uzyskać dostęp do prywatnych członków, jeśli' ChangeData() 'jest' statyczne'. – TheCloudlessSky

+1

Jako przykład języka, który jest inny - w języku Ruby publiczne jest takie samo, ale prywatne oznacza "dostępny tylko przez tę samą instancję", a chronione oznacza "dostępne tylko z tej samej klasy". Dziedziczenie nie ma z tym nic wspólnego. – Tesserex

Odpowiedz

35

Członkowie prywatni są dostępni dla dowolnego kodu w tekście programu tej klasy (także w obrębie typów zagnieżdżonych). Nie ma to nic wspólnego z tym, z którą klasą masz do czynienia.

nie wierzę, to narusza enkapsulacji - API jest jeszcze oddzielone od wykonania, ale realizacja „wie” o sobie bez względu na wystąpienie to patrzy.

Wierzę, że w niektórych innych językach to nie jest jak działa dostępność, ale zdecydowanie jest dla C# i Java. (Java ma nieco inne zasady dotyczące dostępu do prywatnych członków, ale przetłumaczony kod z tego, co napisałeś, nadal będzie działać.)

+3

Implementacja dostępności na poziomie instancji wymagałaby sprawdzenia w czasie wykonywania dla każdego dostępu do zmiennych członkowskich, podczas gdy model ten można sprawdzić podczas kompilacji. –

+1

@ James: Cóż, niekoniecznie.Możesz * wymagać *, aby prywatni członkowie byli dostępni tylko przez "to" odniesienie. To byłoby ohydne, ale możliwe. –

+1

Dodałbym do odpowiedzi Jona, że ​​ten rodzaj kontroli dostępu umożliwia łatwe pisanie operatorów n-ary, takich jak równość. Znacznie trudniej byłoby wdrożyć operator równości, gdyby żadna instancja nie miała dostępu do pozostałych prywatnych członków. –

9

Dzieje się tak, ponieważ C# wymusza prywatność na poziomie klasy, a nie na poziomie obiektu.

Większość języków mainstreamowe egzekwować tę samą politykę, czyli C#, C++ i Java. Myślę, że powodem są:

1), ponieważ programiści są przyzwyczajeni do tego rodzaju polityki;

2) z powodu poziomu obiektu prywatności staną się zbyt uciążliwe w zamian z nielicznych zalet.

+0

Nie wierzę, że być koniecznością użycia "tego", ponieważ kompilatory są w stanie rozróżnić zmienne składowe.Myślę, że byłoby to męczące, gdyby istniała potrzeba posiadania metod pobierających dla każdej wartości członkowskiej klasy, w rzeczywistości, byłoby to sprzeczne z enkapsulacją, ponieważ narażasz prywatnych członków również na inną klasę! – Simone

+0

@ miket2e Spróbuj wprowadzić konstruktora kopiowania lub prostą funkcję równań z prywatnością na poziomie obiektu. To proste w bieżącym C#: return this._somePrivateField.Eq uals (other._somePrivateField) - jeśli możesz uzyskać dostęp do other._somePrivateField, jak zaimplementowałbyś taką funkcję bez dodawania publicznych getterów? –

+1

@MichaelStum: Jedną z zalet posiadania pól typu instance-private lub instance-protected jest to, że dzięki temu jasne jest, że klasy pochodne mogą ponownie wyznaczyć te pola bez naruszania zasady Liskov Substitution Principle. W przeciwnym razie takie ponowne zaaranżowanie może spowodować naruszenie LSP. Coś w stylu "równa się" można zaimplementować, stosując metodę klasy "prywatnej", która akceptuje zawartość innego obiektu (jako grupę oddzielnych parametrów lub używając typu chronionego klasą) i mając 'metoda obiektu przekazuje swój stan do metody" Protected "równa się drugiej. – supercat

Powiązane problemy