Автоматически реализованные геттеры и сеттеры против общедоступных полей

Я вижу много примеров кода для классов С#, который делает это:

public class Point {
    public int x { get; set; }
    public int y { get; set; }
}

Или, в более раннем коде, то же самое с явным личным значением поддержки и без новых автоматически реализованных свойств:

public class Point {
    private int _x;
    private int _y;

    public int x {
        get { return _x; }
        set { _x = value; }
    }

    public int y {
        get { return _y; }
        set { _y = value; }
    }
}

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

public class Point {
    public int x;
    public int y;
}

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

Ответ 1

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

Джефф Этвуд имел дело с этим несколько лет назад. Самым важным моментом, который он ретроспективно отметил, является то, что переход от поля к свойству является критическим изменением в вашем коде; все, что потребляет, должно быть перекомпилировано для работы с новым интерфейсом класса, поэтому, если что-то вне вашего контроля потребляет ваш класс, у вас могут возникнуть проблемы.

Ответ 2

Также гораздо проще изменить его на это позже:

public int x { get; private set; }

Ответ 3

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

Ответ 4

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

С# может обрабатывать свойства и переменные по разному. Например, вы не можете передавать свойства в качестве параметров ref или out. Поэтому, если вам по какой-то причине нужно изменить структуру данных, и вы использовали общедоступные переменные, и теперь вам нужно использовать свойства, ваш интерфейс должен будет измениться, и теперь код, который обращается к свойству x, может не компилироваться, как если бы он был переменным х:

Point pt = new Point();
if(Int32.TryParse(userInput, out pt.x))
{
     Console.WriteLine("x = {0}", pt.x);
     Console.WriteLine("x must be a public variable! Otherwise, this won't compile.");
}

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

Ответ 5

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

Рассмотрим этот код, который сохранит вас в asp.net и который не будет возможен без уровня абстракции, предоставляемого сеттерами и геттерами:

class SomeControl
{

private string _SomeProperty  ;
public string SomeProperty 
{
  if ( _SomeProperty == null ) 
   return (string)Session [ "SomeProperty" ] ;
 else 
   return _SomeProperty ; 
}
}

Ответ 6

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

Например:

public string x { get; set; }

и, например, вы уже много раз используете x и не хотите ломать свой код.

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

Моя идея состоит в том, чтобы добавить новую личную переменную и добавить те же x getter и setter.

private string _x;

public string x { 
    get {return _x}; 
    set {
        if (Datetime.TryParse(value)) {
            _x = value;
        }
    }; 
}

Это то, что вы подразумеваете под гибкостью?

Ответ 7

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

Ответ 8

Кроме того, вы можете поместить точки останова на геттеры и сеттеры, но вы не можете на полях.

Ответ 9

AFAIK сгенерированный интерфейс CIL отличается. Если вы измените открытый элемент на свойство, вы меняете его на публичный интерфейс и вам нужно перестроить каждый файл, который использует этот класс. Это не обязательно, если вы только изменяете реализацию геттеров и сеттеров.

Ответ 10

Возможно, просто создавая поля, вы можете привести к более Anemic Domain Model.

С уважением

Ответ 11

Также стоит отметить, что вы не можете делать Auto Properties Readonly, и вы не можете инициализировать их inline. Обе эти вещи я бы хотел увидеть в будущей версии .NET, но я считаю, что вы не можете делать ни в .NET 4.0.

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

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

Ответ 12

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

Ответ 13

Самое большое отличие заключается в том, что если вы когда-либо измените свою внутреннюю структуру, вы все равно сможете поддерживать геттеры и сеттеры как есть, изменяя свою внутреннюю логику, не вредя пользователям вашего API.

Ответ 14

Если вам нужно изменить способ получения x и y в этом случае, вы можете просто добавить свойства позже. Это то, что я нахожу наиболее запутанным. Если вы используете переменные public member, вы можете легко изменить это свойство позже и использовать частные переменные с именем _x и _y, если вам нужно сохранить значение внутри.

Ответ 15

Сеттеры и геттеры в принципе плохие (они плохой запах OO - я перестану говорить, что они анти-шаблон, потому что они действительно нужны иногда).

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

Способы настройки и геттеры были "Проданы": вам может понадобиться знать, что кто-то получает значение или меняет его, что имеет смысл только с примитивами.

Объекты мешков объектов, такие как DAO, DTO и отображаемые объекты, исключаются из этого правила, поскольку они не являются объектами реального значения "OO Design" слова Object. (Вы не думаете о "Передача сообщений" в DAO, это просто куча пар атрибут/значение).