Вопрос по language-features, language-design, private-members, oop, c# – Грубо говоря, я лично считаю, что написание классов, производных от базового класса, предлагает аналогичную функциональность, которую вы описываете как «наличие личных данных на экземпляр». Вместо этого у вас просто есть новое определение класса для каждого «уникального» типа.

148

(и многих других языках) совершенно законно обращаться к закрытым полям других экземпляров того же типа. Например:

public class Foo
{
    private bool aBool;

    public void DoBar(Foo anotherFoo)
    {
        if (anotherFoo.aBool) ...
    }
}

КакСпецификация C # (разделы 3.5.1, 3.5.2) заявляет, что доступ к закрытым полям имеет тип, а не экземпляр. Я обсуждал это с коллегой, и мы пытаемся найти причину, по которой это работает так (а не ограничивать доступ к одному и тому же экземпляру).

Лучший аргумент, который мы могли бы выдвинуть, - это проверки на равенство, когда класс может захотеть получить доступ к закрытым полям, чтобы определить равенство с другим экземпляром. Есть ли другие причины? Или какая-то золотая причина, которая абсолютно означает, что она должна работать таким образом, или что-то совершенно невозможное?

@Jon Позиция, которая была принята за так называемые «преимущества», заключается в том, что классы не должны знать внутреннее состояние другого экземпляра - независимо от того, что это тот же тип. Не одно преимущество, но, вероятно, есть довольно веская причина выбирать одно из другого, и именно это мы и пытались выяснить. RichK
Это правда, что он не очень хорошо моделирует реальный мир. В конце концов, только то, что моя машина может сообщить, сколько бензина осталось, не означает, что моя машина должна быть в состоянии определить, сколько газа осталось в КАЖДОМ автомобиле. Так что да, я теоретически могу видеть, что у меня есть доступ к "частному экземпляру". Я чувствую, что действительно никогда бы не использовал его, хотя, потому что был бы обеспокоен тем, что в 99% случаев я действительно хотел бы иметь другой экземпляр для доступа к этой переменной. aquinas
Скала обеспечиваетчастный случай члены - наряду со многими другими уровнями доступа, которых нет в Java, C # и многих других языках. Это совершенно законный вопрос. Bruno Reis
Каковы преимущества для альтернативы? Jon Skeet
Вы всегда можете превратить переменную в пару замыканий getter / setter, инициализированных в конструкторе, которые потерпят неудачу, еслиэто не так, как это было во время инициализации ... Martin Sojka

Ваш Ответ

2   ответа
72

что одна из причин, по которой он работает таким образом, заключается в том, что модификаторы доступа работают навремя компиляции, Таким образом, определение того, является ли данный объектток объект не легко сделать. Например, рассмотрим этот код:

public class Foo
{
    private int bar;

    public void Baz(Foo other)
    {
        other.bar = 2;
    }

    public void Boo()
    {
        Baz(this);
    }
}

Может ли компилятор обязательно выяснить, чтоother на самом делеthis? Не во всех случаях. Можно утверждать, что тогда это просто не должно компилироваться, но это означает, что у нас есть путь к коду, где член частного экземпляраправильного экземпляра недоступен, что я думаю, еще хуже.

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

РЕДАКТИРОВАТЬДанил Хилгарт считает, что это рассуждение обратное, имеет смысл. Разработчики языка могут создать язык, который они хотят, и авторы компилятора должны соответствовать ему. При этом у языковых дизайнеров есть некоторый стимул для облегчения работы авторов компиляторов. (Хотя в этом случае достаточно легко утверждать, что частныетолько быть доступным черезthis (либо неявно, либо явно)).

Тем не менее, я считаю, что это делает проблему более запутанной, чем она должна быть. Большинство пользователей (включая меня) сочли бы это излишним ограничением, если вышеприведенный код не работает: в конце концов, этомой данные я пытаюсь получить доступ! Почему я должен пройтиthis?

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

Я не думаю, что аргумент компилятора верен. Вокруг есть языки, которые допускают только частный экземпляр (например, Ruby) и которые по своему выбору допускают частный экземпляр и частный класс (например, Eiffel). Генерация компилятора не была необходима сложнее или проще для этих языков. Для получения дополнительной информации см. Также мой ответ вниз по ветке. Abel
@ Даниэль Точка занята. Я все еще думаю, что это обоснованное соображение, хотя вы, конечно, правы, что в конечном итоге разработчики языка выясняют, чего они хотят, и авторы компиляторов соответствуют этому. dlev
ИМХО, это рассуждение неправильное. Компилятор обеспечивает соблюдение правил языка. Это не делает их. Другими словами, если бы закрытые члены были «частным экземпляром», а не «закрытым типом», компилятор был бы реализован другими способами, например, только позволяяthis.bar = 2 но нетother.bar = 2, потому чтоother может быть другой экземпляр. Daniel Hilgarth
@dlev: Я ничего не сказал о том, считаю ли я, что "частные экземпляры" - это хорошая вещь. :-) Я просто хотел отметить, что вы утверждаете, что техническая реализация диктует правила языка и что, на мой взгляд, эта аргументация не верна. Daniel Hilgarth
@Daniel Это хороший момент, но, как я уже говорил, я думаю, что это ограничение будет хуже, чем видимость на уровне класса. dlev
59

вид инкапсуляции, используемый в C # и подобных языках* заключается в снижении взаимозависимости разных частей кода (классов в C # и Java), а не разных объектов в памяти.

Например, если вы пишете код в одном классе, который использует несколько полей в другом классе, то эти классы очень тесно связаны. Однако, если вы имеете дело с кодом, в котором у вас есть два объекта одного класса, то никакой дополнительной зависимости нет. Класс всегда зависит от самого себя.

Однако вся эта теория об инкапсуляции терпит неудачу, как только кто-то создает свойства (или получает / устанавливает пары в Java) и выставляет все поля напрямую, что делает классы такими связанными, как если бы они в любом случае обращались к полям.

* Для уточнения видов инкапсуляции см. Отличный ответ Авеля.

@ Goran Хотя я согласен, что это не было бы идеально, он все еще не полностью потерпел неудачу, так как методы доступа get / set позволяют добавить дополнительную логику, если, например, изменяются базовые поля. ForbesLindesay
@Ken: Это не удастся, если вы предоставите свойство для каждого поля, которое у вас есть, даже не задумываясь о том, должно ли оно быть открыто. Goran Jovic
Я не думаю, что это однажды потерпит неудачуget/set методы предоставляются. Методы доступа по-прежнему поддерживают абстракцию (пользователю не нужно знать, что за ним есть поле или какие поля могут быть за свойством). Например, если мы пишемComplex класс, мы можем выставить свойства, чтобы получить / установить полярные координаты, а другой получить / установить для декартовых координат. Какой класс использует класс, неизвестно пользователю (это может быть что-то совершенно другое). Ken Wayne VanderLinde

Похожие вопросы