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

StackOverflow https://stackoverflow.com/questions/111461

  •  02-07-2019
  •  | 
  •  

Вопрос

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

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;
}

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

Это было полезно?

Решение

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

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

Другие советы

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

public int x { get; private set; }

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

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

C # иногда может обрабатывать свойства и переменные по-разному.Например, вы не удается передать свойства в качестве параметров ref или out.Поэтому, если вам по какой-то причине нужно изменить структуру данных, и вы использовали общедоступные переменные, а теперь вам нужно использовать свойства, ваш интерфейс придется изменить, и теперь код, который обращается к свойству x, может больше не компилироваться, как это было, когда это была переменная 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.");
}

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

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

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

class SomeControl
{

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

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

Например:

public string x { get; set; }

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

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

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

private string _x;

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

Это то, что вы имеете в виду, делая его гибким?

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

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

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

Может быть, простое обнародование полей, которые вы могли бы сделать, приведет вас к большему Модель Анемичной предметной области.

С наилучшими пожеланиями

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

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

Также в этих ситуациях я устанавливаю резервные поля напрямую, когда значения передаются из конструктора (нет необходимости пытаться запустить OnPropertyChangedEvent (который в любом случае был бы НУЛЕВЫМ в это время), где бы еще я ни использовал само свойство.

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

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

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top