Я вижу много примеров кода для классов 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;
}
Чтобы быть ясным, я понимаю ценность геттеров и сеттеров, когда вам нужно сделать некоторый перевод базовых данных. Но в случаях, когда вы просто передаете значения, это кажется излишне многословным.





Он инкапсулирует настройку и доступ к этим членам. Если через какое-то время разработчику кода потребуется изменить логику при обращении к члену или его установке, это можно сделать без изменения контракта класса.
@ Ajedi32 технически это нет один и тот же контракт. Если вы измените его с поля на свойство (или свойство на поле), вам придется перекомпилировать все, что обращается к этому члену. Потому что скомпилированный IL отличается при доступе к свойству и полю.
Никогда не знаешь, может, позже тебе не понадобится перевод данных. Вы готовы к этому, если спрячете своих членов. Пользователи вашего класса не заметят, если вы добавите перевод, поскольку интерфейс останется прежним.
Самая большая разница в том, что даже если вы измените свою внутреннюю структуру, вы все равно сможете поддерживать геттеры и сеттеры как есть, изменяя их внутреннюю логику, не причиняя вреда пользователям вашего API.
Также гораздо проще изменить его на это позже:
public int x { get; private set; }
Я ... даже не знал, что ты можешь это сделать.
Правда, это очень полезно, к сожалению, в интерфейсе этого сделать нельзя.
Я склонен согласиться (что кажется излишне подробным), хотя это проблема, которую наша команда еще не решила, и поэтому наши стандарты кодирования по-прежнему настаивают на подробных свойствах для всех классов.
Джефф Этвуд занимался этим несколько лет назад. Самым важным моментом, который он ретроспективно отметил, является то, что переход от поля к свойству - это нарушение изменения в вашем коде; все, что потребляет его, должно быть перекомпилировано для работы с новым интерфейсом класса, поэтому, если что-то вне вашего контроля потребляет ваш класс, у вас могут возникнуть проблемы.
Спасибо за эту ссылку и за то, что убедили меня, что при переключении поля / свойства что-то действительно сломается. Мне это странно, так как синтаксис все равно один и тот же.
Вы могли подумать, что все сводится к одному и тому же, но очевидно, что внутренняя механика немного отличается.
В C# свойство с get и set компилируется в пару методов, таких как get_PropertyName () и set_PropertyName (значение типа). Синтаксис свойств в C# - это просто синтаксический сахар. Свойства могут выполнять код, поэтому для них не имело бы смысла компилировать до того же кода, что и для поля.
Компиляторы JIT оптимизируют свойство без кода, чтобы оно было эквивалентно полю, поэтому нет причин не использовать свойства с учетом сокращенного синтаксиса в C# 3.0+.
Если вам нужно изменить способ получения x и y в этом случае, вы можете просто добавить свойства позже. Вот что меня больше всего сбивает с толку. Если вы используете общедоступные переменные-члены, вы можете легко изменить это на свойство позже и использовать частные переменные с именами _x и _y, если вам нужно сохранить значение внутри.
Идея состоит в том, что даже если необходимо изменить базовую структуру данных, открытый интерфейс класса менять не нужно.
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.");
}
Использование свойств с самого начала позволяет избежать этого, и вы можете свободно настраивать базовую реализацию сколько угодно, не нарушая клиентский код.
AFAIK сгенерированный интерфейс CIL отличается. Если вы меняете публичный член на свойство, вы меняете его публичный интерфейс, и вам нужно перестраивать каждый файл, который использует этот класс. В этом нет необходимости, если вы изменяете только реализацию геттеров и сеттеров.
Также следует учитывать влияние изменения на общедоступные члены, когда дело касается привязки и сериализации. Оба они часто полагаются на общедоступные свойства для получения и установки значений.
Может быть, просто сделав поля общедоступными, вы можете перейти к большему количеству Модель анемического домена.
С уважением
Сеттеры и геттеры в принципе плохи (от них дурной запах объектно-ориентированного программирования - я не буду говорить, что они являются анти-паттерном, потому что они действительно иногда необходимы).
Нет, технически разницы нет, и когда я действительно хочу предоставить общий доступ к объекту в наши дни, я иногда делаю его общедоступным final вместо добавления геттера.
Способ «продажи» сеттеров и геттеров заключается в том, что вам может потребоваться знать, что кто-то получает значение или изменяет его, что имеет смысл только с примитивами.
Объекты пакета свойств, такие как DAO, DTO и экранные объекты, исключаются из этого правила, потому что они не являются объектами в реальном значении слова Object в «OO Design». (Вы не думаете о «передаче сообщений» в DAO, это просто куча пар атрибут / значение).
Setter и Getter позволяют добавлять дополнительный уровень абстракции, и в чистом ООП вы всегда должны получать доступ к объектам через интерфейс, который они предоставляют внешнему миру ...
Рассмотрим этот код, который спасет вас в asp.net и который был бы невозможен без уровня абстракции, обеспечиваемого сеттерами и геттерами:
class SomeControl
{
private string _SomeProperty ;
public string SomeProperty
{
if ( _SomeProperty == null )
return (string)Session [ "SomeProperty" ] ;
else
return _SomeProperty ;
}
}
Поскольку автоматически реализованные геттеры принимают одно и то же имя для свойства и фактических переменных частного хранилища. Как вы можете это изменить в будущем? Я думаю, что речь идет о том, что вместо поля используйте реализованный auto, чтобы вы могли изменить его в будущем, если вам нужно добавить логику для геттера и сеттера.
Например:
public string x { get; set; }
и, например, вы уже много раз используете x и не хотите нарушать свой код.
Как изменить установщик автоматического получения ... например, для установщика разрешается устанавливать только допустимый формат телефонного номера ... как изменить код, чтобы изменить только класс?
Моя идея - добавить новую частную переменную и добавить те же средства получения и установки x.
private string _x;
public string x {
get {return _x};
set {
if (Datetime.TryParse(value)) {
_x = value;
}
};
}
Это то, что вы имеете в виду, говоря о гибкости?
Кроме того, вы можете ставить точки останова на геттеры и сеттеры, но не на поля.
Также стоит отметить, что вы не можете сделать автоматические свойства только для чтения и не можете инициализировать их встроенными. Обе эти вещи я хотел бы увидеть в будущих версиях .NET, но я считаю, что вы не сможете сделать ни то, ни другое в .NET 4.0.
В наши дни я использую резервное поле со свойствами только тогда, когда мой класс реализует INotifyPropertyChanged, и мне нужно активировать событие OnPropertyChanged при изменении свойства.
Также в этих ситуациях я устанавливаю поля поддержки напрямую, когда значения передаются из конструктора (нет необходимости пытаться запустить событие OnPropertyChangedEvent (которое в любом случае будет NULL в это время), в любом другом месте, где я использую само свойство.
Это не совсем так, у вас могут быть автоматически реализованные свойства только для чтения (или только для записи), если у вас есть SomePropName {get; private set;}, а затем установить свойство с помощью инициализаторов объекта ..
why we dont just use public fields instead of using properties then call accessors ( get,set ) when we dont need to make validations ?
Добавление получателя и сеттера делает переменную свойством, как при работе в Wpf / C#.
Если это просто общедоступная переменная-член, она недоступна из XAML, потому что это не свойство (даже если его общедоступная переменная-член).
Если у него есть сеттер и получатель, то он доступен из XAML, потому что теперь это свойство.
Но как это меняет контракт класса? В любом случае
point.x = 1;иpoint.xработают нормально.