Почему переменная частного члена может быть заменена экземпляром класса?

class TestClass
{
    private string _privateString = "hello";
    void ChangeData()
    {
        TestClass otherTestClass = new TestClass();
        otherTestClass._privateString = "world";
    }
}

Этот код компилируется в С#, и эквивалент работает в PHP, но может ли кто-нибудь объяснить причину, по которой otherTestClass._privateString можно изменить здесь?

Я бы подумал, что экземпляр класса не сможет изменять переменную частного члена ни при каких обстоятельствах, и что попытка доступа к otherTestClass._privateString даст ошибку "недосягаемый из-за уровня защиты".

Это не так, поэтому, почему создание экземпляра объекта внутри его собственного класса позволяет вам получить доступ к закрытым членам? И должно ли это, разве это не разрывает инкапсуляцию до такой степени? Или я пропущу что-то очевидное?

  • (Я не спрашиваю, является ли вышеуказанный класс дизайном хорошей практикой, просто интересуется теорией, стоящей за ней.)

Изменить - Спасибо за ответы и комментарии. Чтобы уточнить, мне также интересно узнать, является ли возможность сделать это, считается положительной особенностью, или если это необходимый компромисс для лучшей проверки времени компиляции/ясности кода/потому что большинство других языков делает это так или иначе. Мне кажется, что в идеале компилятор предупредил бы вас об этом, но тогда я далек от разработчика языка. Любые примеры того, как именно это позволяет вам сделать что-то полезное (без нарушения инкапсуляции), которое в противном случае было бы трудным или невозможным, было бы здорово.

Ответ 1

Частные члены доступны для любого кода в тексте программы этого класса (в том числе внутри вложенных типов). Это не имеет никакого отношения к тому экземпляру класса, с которым вы имеете дело.

Я не считаю, что это нарушает инкапсуляцию - API все еще отделен от реализации, но реализация "знает" о себе независимо от того, на каком экземпляре он смотрит.

Я считаю, что на некоторых других языках это не так, как работает доступность, но это определенно для С# и Java. (Java имеет несколько иные правила о том, что может получить доступ к закрытым членам, но переведенный код для того, что вы написали, все равно будет работать.)

Ответ 2

Это связано с тем, что С# обеспечивает конфиденциальность на уровне класса, а не конфиденциальность на уровне объекта.

В большинстве основных языков применяется одна и та же политика, например, С#, С++ и Java. Я думаю, что причина такова:

1), потому что разработчики привыкли к такой политике;

2), поскольку конфиденциальность на уровне объектов станет слишком утомительной в результате получения очень немногих преимуществ.