Зачем инкапсулировать это поле? [дубликат]


На этот вопрос уже есть ответ здесь:

Мне всегда говорили инкапсулировать все свойства из класса...

Это верно:

private string propertyName;
public string PropertyName
{
    get { return propertyName; }
    set { propertyName = value; }
}

И это неправильно

Public string PropertyName;

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

Так что если кто-то может оправдать инкапсуляцию по этому сценарию. (Я могу понять по другим сценариям).

8 5

8 ответов:

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

Дело в том, что есть некоторые случаи, когда вы не можете безопасно изменить его позже:
  • Если вы компилируете Foo.dll с публичным полем, а кто-то строит бар.dll, которая ссылается на Foo.проблемы, вы не может позже упасть в новой версии Foo.dll с этим полем изменяется на свойство. Вам придется заставить этого другого человека перестроить бар.dll против вашего нового Фу.файл DLL. Для некоторых магазинов это не проблема; для других это может быть огромной проблемой.
  • Если вы пишете какой-либо код отражения, отражение полей сильно отличается от отражения свойств. Поэтому, если вы позже измените свое поле на свойство, ваш код отражения сломается.

Насколько важны оба из них эти сценарии? Наверное, не очень. Но проще заранее написать

public string PropertyName { get; set; }

Чем это, чтобы очистить беспорядок, если Вы действительно должны изменить его позже.

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

Ваша главная жалоба-это многословие первой реализации. Ваш синтаксис читается как C# для меня, так что public String PropertyName{get;set;} будет менее подробным, но эквивалентным утверждением. Полезность заключается в том, что вы можете изменить базовую реализацию свойства, не меняя использования. Стиль кодирования для полей и свойств обычно меняется, так что это приведет, по крайней мере, к рефакторингу интерфейса, который может быть болезненным, если он подвергается воздействию других.

Да, это перебор большую часть времени. время.

Обновление: Основываясь на комментариях ниже, я добавлю немного о различиях, которые компилятор отмечает между полями и свойствами. Вы не можете использовать свойство в качестве аргумента ref или out, и, как было отмечено ниже Робертом Леви, в то время как код читает то же самое, есть вызов функции, скрытый компилятором, поэтому вам нужно перекомпилировать зависимые сборки. Вы можете поместить свойство в интерфейс, но не в поле. Так что есть некоторые плюсы и минусы.

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

Если вы начнете с public string PropertyName; , но позже переключитесь на определение реального свойства, другие классы, использующие ваш, должны будут быть перекомпилированы (даже если их фактический код не должен будет меняться).

В более новых версиях C# для этого есть сокращение: public string MyProperty {get; set; }, которое за кулисами создает закрытый член, который вы (в данный момент) не используете.

Потому что вы можете изменить, например, set позже, чтобы выполнить проверку. Это невозможно с public string PropertyName, так что вы будете застрять с публичным атрибутом навсегда.


Как говорили другие в их ответы , вы можете удалить некоторые из cruft, используя следующий синтаксис:

public string PropertyName { get; set; }

Вы инкапсулируете для обеспечения целостности данных. Например, если у вас есть атрибут возраста для класса person, вы не хотите, чтобы кто-то хранил большое число, например 19348, в этой переменной. Если вы используете инкапсуляцию, вы можете проверить это число и выполнить обработку ошибок, когда пользователь пытается сделать что-то подобное. И под "пользователем" я подразумеваю другого программиста, использующего ваш класс.

Еще один пример. Вы можете легко переопределить свойство во время наследования.

class Base
{
    public virtual string PropertyName { get; set; }
}

class Derived : Base
{
    public override string PropertyName
    {
        get
        {
            return base.PropertyName + " Something";
        }
        set
        {
            base.PropertyName = value;
        }
    }
}

Инкапсуляция позволяет изменять детали реализации без изменения интерфейса к классу (это означает, что код, использующий класс, не нуждается в изменении). Например, вы можете позже добавить некоторую проверку или другую логику, которая изменяет вещи внутренне как побочный эффект этого изменения свойства, или даже заменяет базовое хранилище для свойства), и все это без необходимости изменять что-либо, использующее этот класс.

Хорошая привычка всегда инкапсулировать данные, даже если вы не видите необходимости сейчас (и особенно потому, что большинство современных IDE автоматически генерируют геттеры и сеттеры для вас).

Я думаю, что общая идея инкапсуляции методов доступа заключается в том, чтобы сделать код более гибким в будущем (т. е. хорошая практика программирования).

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

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