Почему и как С# разрешает доступ к закрытым переменным вне самого класса, когда он находится внутри одного и того же содержащего класса?

Я не знаю, достаточно ли описательный вопрос, но почему и как это поведение существует?:

public class Layer
{
    public string Name { get; set; }

    private IEnumerable<Layer> children;
    public IEnumerable<Layer> Children
    {
        get { return this.children.Where ( c => c.Name != null ).Select ( c => c ); }
        set { this.children = value; }
    }

    public Layer ( )
    {
        this.children = new List<Layer> ( ); // Fine

        Layer layer = new Layer ( );
        layer.children = new List<Layer> ( ); // Isn't .children private from the outside?
    }
}

Я могу получить доступ к layer.Children в любом месте, это прекрасно, но как я могу получить доступ к layer.Children, так как он закрыт?

Layer layer = new Layer ( );
layer.children = new List<Layer> ( );

работает только в том случае, если код находится внутри класса Layer. Есть ли специальный код для обработки доступа к частным переменным по-разному, если он выполняется внутри содержащего класса, хотя доступ извне?

Я знаю причину использования:

this.children = ...

внутри содержащего класса, но создавая новые экземпляры и изменяя их извне, даже если они все еще находятся в пределах содержащего класса, не кажется хорошей практикой.

В чем причина этого?

Ответ 1

См. раздел 3.5.1 спецификации языка С#. Соответствующий текст таков:

Частный, который выбран включая частный модификатор в член. Интуитивно понятный значение частного - "доступ ограничен к содержащему типу".

Обратите внимание, что модификатор относится к типу, а не к экземпляру.

И далее в разделе 3.5.2 дополнительно разъясняются некоторые правила:

В интуитивных терминах, когда тип или доступ к элементу M, шаги оцениваются для обеспечения того, чтобы доступ разрешен:

  • Во-первых, если M объявлено внутри типа (в отличие от единицы компиляции или пространство имен), ошибка времени компиляции если этот тип недоступен.
  • Затем, если M является общедоступным, доступ разрешен.
  • В противном случае, если M защищено внутренним, доступ разрешен, если это происходит в рамках программы, в которой M объявляется, или если оно происходит внутри класс, полученный из класса в который M объявлен и имеет место через тип производного класса (§3.5.3).
  • В противном случае, если M защищен, доступ разрешен, если он возникает в классе, в котором M объявляется, или если это происходит в пределах класс, полученный из класса, в котором M объявляется и проходит через тип производного класса (п. 3.5.3).
  • В противном случае, если M является внутренним, доступ разрешен, если он возникает в рамках программы, в которой M объявлен.
  • В противном случае, если M является приватным, доступ разрешен, если он возникает в пределах типа, в котором M объявлен.
  • В противном случае тип или элемент недоступен, а ошибка времени компиляции происходит.

Ответ 2

Это общий дизайн. Он предположил, что тот, кто написал класс, знает, как правильно работать с ним и понимает, что означает прямой доступ к частным членам. Поэтому доступ к частным членам других экземпляров одного и того же класса часто работает. Если вы знакомы с конструкцией С++ friend, то это похоже на экземпляры одного и того же класса, все друзья друг с другом (хотя С# официально не имеет понятия friend).

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

Ответ 3

Помните, что модификатор частного доступа говорит Private members are accessible only within the body of the class or the struct in which they are declared. Это описание сбивает с толку, но ясно, что ограничение на уровне класса и NOT OBJECT LEVEL. В этом случае слой все еще находится в классе.

Это обсуждалось здесь раньше. мы можем получить доступ к частной переменной с помощью объекта