Свойства против полей: нужна помощь в понимании использования свойств над полями
Прежде всего, я прочитал список публикаций на эту тему, и я не чувствую, что понял свойства из-за того, что я понял о инкапсуляции и модификаторах полей (private, public..ect).
Одним из основных аспектов C#, который я изучил, является важность защиты данных в вашем коде с помощью инкапсуляции. Я "думал", что понял, что это из-за возможности использования модификаторов (частных, общедоступных, внутренних, защищенных). Однако, узнав о свойствах, я как бы разрываюсь с пониманием не только использования свойств, но и общей важности / способности защиты данных (то, что я понимал как инкапсуляция) в C#.
Чтобы быть более конкретным, все, что я прочитал, когда попал в свойства в C#, это то, что вы должны пытаться использовать их вместо полей, когда можете, из-за:
1) они позволяют вам изменять тип данных, когда вы не можете напрямую получить доступ к полю.
2) они добавляют уровень защиты доступа к данным
Однако из того, что я "подумал", что я узнал об использовании модификаторов полей, я узнал, что свойства просто генерируют дополнительный код, если только у вас нет причин менять тип (#1) - потому что вы (более или менее) создание скрытых методов для доступа к полям, а не напрямую.
Кроме того, в Properties можно добавить целые модификаторы, что еще больше усложняет мое понимание необходимости свойств для доступа к данным.
Я прочитал несколько глав от разных авторов о "свойствах", и ни одна из них не дала объяснения хорошему пониманию свойств по сравнению с полями и инкапсуляцией (и хорошими методами программирования).
Может кто-нибудь объяснить:
1) почему я хотел бы использовать свойства вместо полей (особенно когда это появляется, я просто добавляю дополнительный код
2) есть ли какие-либо советы по распознаванию использования свойств и не видению их как простых методов (за исключением того, что get; набор очевиден) при отслеживании кода других людей?
3) Какие-нибудь общие правила, когда дело доходит до хороших методов программирования, когда и что использовать?
Спасибо и извините за длинный пост - я не хотел просто задавать вопрос, который был задан 100 раз, не объясняя, почему я спрашиваю его снова.
12 ответов
Вам не нужно беспокоиться о дополнительном коде, необходимом для доступа к полям через свойства, он будет "оптимизирован" компилятором JIT (путем вставки кода). За исключением случаев, когда он слишком велик, чтобы быть встроенным, но в любом случае вам понадобился дополнительный код.
И дополнительный код для определения простых свойств также минимален:
public int MyProp { get; set; } // use auto generated field.
Когда вам нужно настроить, вы всегда можете определить свое собственное поле позже.
Таким образом, у вас остается дополнительный уровень инкапсуляции / защиты данных, и это хорошо.
Мое правило: выставлять поля всегда через свойства
1) почему я хотел бы использовать свойства вместо полей (особенно когда это появляется, я просто добавляю дополнительный код
Вы должны всегда использовать свойства, где это возможно. Они абстрагируют прямой доступ к полю (который создается для вас, если вы его не создаете). Даже если свойство не делает ничего, кроме установки значения, оно может защитить вас позже. Изменение поля на свойство позже является критическим изменением, поэтому, если у вас есть открытое поле и вы хотите изменить его на публичное свойство, вам придется перекомпилировать весь код, который первоначально обращался к этому полю.
2) есть ли какие-либо советы по распознаванию использования свойств и не видению их как простых методов (за исключением того, что get; набор очевиден) при отслеживании кода других людей?
Я не совсем уверен в том, что вы спрашиваете, но при трассировке чужого кода вы всегда должны предполагать, что свойство делает что-то иное, чем просто получение и установка значения. Хотя принято не помещать большие объемы кода в методы получения и установки, нельзя просто предполагать, что, поскольку это свойство, оно будет вести себя быстро.
3) Какие-нибудь общие правила, когда дело доходит до хороших методов программирования, когда и что использовать?
Я всегда использую свойства, чтобы получить и установить методы, где это возможно. Таким образом, я могу добавить код позже, если мне нужно будет проверить, что значение находится в определенных границах, не равно нулю и т. Д. Без использования свойств я должен вернуться и поставить эти проверки в каждом месте, к которому я непосредственно обращался к полю.
Одна из приятных особенностей Properties - то, что получатель и установщик могут иметь разные уровни доступа. Учти это:
public class MyClass {
public string MyString { get; private set; }
//...other code
}
Это свойство может быть изменено только изнутри, скажем, в конструкторе. Прочитайте о Внедрении Зависимости. Внедрение в конструктор и вложение свойств имеют дело с установкой свойств из некоторой формы внешней конфигурации. Есть много рамок там. Если вы углубитесь в некоторые из них, вы получите хорошее представление о свойствах и их использовании. Инъекция зависимости также поможет вам ответить на третий вопрос о хорошей практике.
Глядя на код других людей, вы можете определить, является ли что-то методом или свойством, потому что их значки отличаются. Кроме того, в Intellisence первой частью краткого описания свойства является слово Property.
Хотя мне абсолютно не нравится прямое раскрытие полей для общественности, есть еще одна вещь: поля не могут быть открыты через интерфейсы; Свойства могут.
Есть несколько причин, почему вы можете использовать свойства над полями, вот только пара:
а. Имея следующее
public string MyProperty { get; private set; }
Вы делаете свойство "только для чтения". Никто, использующий ваш код, не может изменить его значение. Есть случаи, когда это не совсем верно (если ваша собственность является списком), но они известны и имеют решения.
б. Если вы решили, что вам нужно повысить безопасность своего кода, используйте свойства:
public string MyProperty { get { return _myField; } set { if (!string.IsNullOrEmpty(value)) { _myField = value; } } }
Вы можете сказать, что они свойства, потому что у них нет
()
, Компилятор скажет вам, если вы попытаетесь добавить скобки.Хорошей практикой считается всегда использовать свойства.
Существует много сценариев, в которых использование простого поля не нанесло бы ущерба, но
Свойство можно изменить позже, т. е. если вы хотите добавить событие при каждом изменении значения или выполнить некоторую проверку значения / диапазона.
Также, если у вас есть несколько проектов, которые зависят друг от друга, вы должны перекомпилировать все, что зависит от того, где поле было изменено на свойство.
Использование полей обычно практикуется в частных классах, которые не предназначены для обмена данными с другими классами. Когда мы хотим, чтобы наши данные были доступны другим классам, мы используем свойства, которые имеют возможность обмениваться данными с другими классами через get
а также set
которые называются методами доступа Auto Properties
которые имеют доступ к данным в закрытых классах, также вы можете использовать оба с модификаторами доступа в том же классе, что позволяет классу использовать данные конфиденциально в качестве поля данных и в то же время связать частное поле со свойством, которое делает данные доступными для других классы, см. этот простой пример:
private string _name;
public string Name
{
get
{
return _name;
}
set
{
_name = value;
}
}
Частная строка _name
используется только классом, в то время как Name
свойство доступно другим классам в том же пространстве имен.
why I would want to use properties instead of fields (especially when it appears I am just adding additional code
Вы хотите использовать свойства над полями, потому что, когда вы используете свойства, вы можете использовать события с ними, поэтому в случае, когда вы хотите выполнить какое-либо действие при изменении свойства, вы можете привязать некоторые обработчики к событиям PropertyChanging или PropertyChanged. В случае полей это невозможно. Поля могут быть как открытыми, так и частными или защищенными, в случае реквизитов вы можете сделать их доступными только для чтения, но частными для записи.
any tips on recognizing the use of properties and not seeing them as simply methods (with the exception of the get;set being apparent) when tracing other peoples code?
Метод должен использоваться, когда ожидается, что возвращаемое значение будет динамическим при каждом вызове, а свойство должно использоваться, когда возвращаемое значение не настолько динамично.
Any general rules of thumb when it comes to good programming methods in relation to when to use what?
Да, я настоятельно рекомендую ознакомиться с рекомендациями по проектированию фреймворка для лучших практик хорошего программирования.
Свойства позволяют вам делать вещи, отличные от заданных, или получать значения при их использовании. В частности, они позволяют вам делать логику проверки.
Лучшей практикой является сделать что-либо доступным для общественности. Таким образом, если вы позже измените логику set/get, вам нужно будет только перекомпилировать ваш класс, а не каждый класс, связанный с ним.
Свойства являются предпочтительным способом покрытия полей для обеспечения инкапсуляции. Тем не менее, они функциональны в том смысле, что вы можете выставить свойство другого типа и маршалировать приведение; вы можете изменить модификаторы доступа; они используются в привязке данных WinForms; они позволяют встраивать лёгкую логику для каждого свойства, такую как уведомления об изменениях; и т.п.
При взгляде на код других людей, свойства имеют различные значки intellisense для методов.
Если вы думаете, что свойства - это просто дополнительный код, я бы поспорил с ними в любом случае, но упростил бы вашу жизнь, автоматически сгенерировав свойство из поля (щелкните правой кнопкой мыши -> Refactor -> Encapsulate Field...)
Одно предостережение заключается в том, что такие вещи, как "Threading.Interlocked.Increment" могут работать с полями, но не могут работать со свойствами. Если два потока одновременно вызывают Threading.Interlocked.Increment для SomeObject.LongIntegerField, значение будет увеличено на два, даже если нет другой блокировки. Напротив, если два потока одновременно вызывают Threading.Interlocked.Increment для SomeObject.LongIntegerProperty, значение этого свойства может быть увеличено на два, или на единицу, или на -4,294,967,295, или кто знает, какие другие значения (свойство может быть записано использовать блокировку, предотвращающую значения, отличные от одного или двух в этом сценарии, но это не могло быть записано, чтобы гарантировать правильное увеличение на два).
Я собирался сказать, что свойства (сеттеры) являются отличным местом для создания событий, таких как NotifyPropertyChanged, но кто-то другой опередил меня.
Еще одна веская причина для рассмотрения свойств: допустим, вы используете фабрику для создания некоторого объекта, который имеет конструктор по умолчанию, и вы готовите объект через его свойства.
new foo(){Prop1 = "bar", Prop2 = 33, ...};
Но если внешние пользователи обновляют ваш объект, может быть, есть какие-то свойства, которые вы хотите, чтобы они считали доступными только для чтения и не могли быть установлены (только фабрика должна иметь возможность устанавливать их)? Вы можете сделать сеттеры внутренними - это работает, конечно, только если класс объекта находится в той же сборке, что и фабрика.
Есть и другие способы достижения этой цели, но использование свойств и изменяющейся видимости акселератора целесообразно, если вы занимаетесь разработкой на основе интерфейса или открываете библиотеки для других и т. Д.