Автоматически реализованные методы получения и установки по сравнению с открытыми полями - PullRequest
71 голосов
/ 21 сентября 2008

Я вижу много примеров кода для классов 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;
}

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

Ответы [ 15 ]

47 голосов
/ 21 сентября 2008

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

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

31 голосов
/ 21 сентября 2008

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

public int x { get; private set; }
9 голосов
/ 21 сентября 2008

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

8 голосов
/ 21 сентября 2008

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

C # может по-разному обрабатывать свойства и переменные. Например, вы не можете передать свойства в качестве параметров 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.");
}

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

3 голосов
/ 08 сентября 2009

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

Например:

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

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

3 голосов
/ 22 апреля 2009

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

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

class SomeControl
{

private string _SomeProperty  ;
public string SomeProperty 
{
  if ( _SomeProperty == null ) 
   return (string)Session [ "SomeProperty" ] ;
 else 
   return _SomeProperty ; 
}
}
2 голосов
/ 08 сентября 2009

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

2 голосов
/ 21 сентября 2008

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

1 голос
/ 08 сентября 2009

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

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

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

1 голос
/ 21 сентября 2008

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

С уважением

...