Были ли тривиальные свойства когда-либо спас ваш бекон?
Там много советов, что вы не должны публиковать свои поля публично и вместо этого использовать тривиальные свойства. Я вижу это снова и снова.
Я понимаю аргументы, но Я не думаю, что это хороший совет в большинстве случаев.
Есть ли у кого-нибудь пример времени, когда это действительно имело значение? При написании тривиального свойства сделало что-то важное в будущем (или если вы не использовали его, чтобы получить реальную проблему)?
EDIT: аргумент DataBinding правильный, но не очень интересный. Это ошибка в коде DataBinding, что он не будет принимать публичные поля. Таким образом, мы должны писать свойства, чтобы обойти эту ошибку, а не потому, что свойства - это разумный выбор дизайна класса.
EDIT: Чтобы быть ясным, я ищу примеры из реального мира, а не теории. Время, когда это действительно имело значение.
EDIT: способность установить точку останова на сеттере кажется ценной. Проектирование моего кода для отладчика является неудачным: я бы предпочел, чтобы отладчик стал более умным, но, учитывая отладчик, который у нас есть, я возьму эту способность. Хороший материал.
Ответы
Ответ 1
Может быть, трудно сделать работу кода в неопределенном будущем, но это не может быть оправданием для лени. Кодирование свойства над полем является условным и прагматичным. Назовите это защитным программированием.
Другие люди также будут жаловаться на то, что существует проблема скорости, но JIT'er достаточно умен, чтобы сделать это примерно так же быстро, как обнародовать публичное поле. Очень быстро, что я никогда не заметлю.
Некоторые нетривиальные вещи, которые приходят на ум
- Публичное поле полностью открыто, вы не можете вводить семантику только для чтения или только для записи.
- Свойство может иметь различную
get
по сравнению с set
доступность (например, public get, внутренний набор)
- Вы не можете переопределить поле, но вы можете иметь виртуальные свойства.
- Ваш класс не имеет контроля над публичным полем
- Ваш класс может управлять свойством. Он может ограничить установку допустимым диапазоном значений, флаг, что состояние было изменено, и даже lazy-load значение.
- Сложность отражения различна. Публичное поле не является собственностью.
- Нет привязки данных, как указывают другие. (Это только ошибка для вас. - Я понимаю, почему дизайнеры каркасов .net не поддерживают шаблоны, которые они не поддерживают.)
- Вы не можете поместить поле в интерфейс, но вы можете поместить свойство на интерфейс.
- Ваше имущество не требует хранения данных. Вы можете создать фасад и отправить в содержащийся объект.
Вы вводите только 13 символов для правильности. Это вряд ли похоже на спекулятивную общность. Существует семантическая разница, и, если не что иное, свойство имеет другое смысловое значение и является гораздо более гибким, чем публичное поле.
public string Name { get; set; }
public string name;
Я помню один раз, когда сначала использовал .net. Я закодировал несколько классов как просто поля, а затем мне нужно было как-то их использовать как свойства, и это была полная трата времени, когда я мог просто сделать это в первый раз.
Итак, какие у вас причины для несоблюдения конвенции? Почему вы чувствуете необходимость плавать вверх по течению? Что это спасло вас от этого?
Ответ 2
У меня было тривиальное свойство, которое я пару раз спасал при отладке..Net не поддерживает концепцию точки прерывания данных (чтение или запись). Иногда при отладке очень сложного сценария важно отслеживать чтение/запись определенного свойства. Это легко с собственностью, но невозможно с полем.
Если вы не работаете в производственной среде, вам просто нужно реорганизовать свойство field → для отладки. Иногда вы попадаете в ошибки, которые воспроизводятся только в производственной среде, которую сложно исправить с помощью нового двоичного файла. Свойство может спасти вас здесь.
Это довольно сдержанный сценарий.
Ответ 3
Раньше я думал об одном и том же, Джей. Зачем использовать свойство, если оно доступно только для прямого доступа к частному члену? Если вы можете описать его как автопромышленность, то наличие собственности, а не поля, казалось, было глупо. Даже если вам когда-либо понадобится изменить реализацию, вы всегда можете просто реорганизовать в недвижимость позже, и любой зависимый код все равно будет работать, верно?. Ну, может быть, нет.
Видите ли, я недавно видел свет на тривиальных свойствах, поэтому, возможно, теперь я могу помочь вам сделать то же самое.
То, что окончательно убедило меня, было довольно очевидным (в ретроспективе), что свойства в .Net - это просто синтаксический сахар для методов getter и setter, и эти методы имеют другое имя от самого свойства. Код в той же сборке все равно будет работать, потому что в любом случае вам придется перекомпилировать его в одно и то же время. Но любой код в другой сборке, которая ссылается на вашу, будет терпеть неудачу, если вы реорганизуете поле в свойство, если оно не перекомпилируется в отношении вашей новой версии в одно и то же время. Если это свойство с самого начала, все по-прежнему хорошо.
Ответ 4
Часть идеи состоит в том, что эти свойства не могут быть тривиальными в будущем - если вы связали внешний код с полем и позже захотите обернуть его в свойстве, все зависимые коды должны будут измениться, и вы можете не сможете этого сделать, особенно в том случае, если вы являетесь разработчиком управления или имеете библиотеки, которые вы не можете контролировать, и т.д.
Не говоря уже о некоторых методах .NET, которые не позволят вам особенно использовать привязку полей.
Я уверен, что есть и другие веские причины. Почему это имеет значение для вас? Используйте автоматическое свойство и выполняйте его. Кажется, что-то не стоит беспокоиться обо мне...
Ответ 5
Я отвечу на ваш вопрос другим: действительно ли вам когда-либо помогали не публиковать все ваши типы и члены? Я подозреваю, что я не предотвратил никаких ошибок. Тем не менее, я инкапсулировал свои типы должным образом, только разоблачая то, что должно было быть раскрыто. Свойства похожи - хороший дизайн больше всего на свете. Я думаю о свойствах, концептуально отличных от полей; они являются частью контракта, а не являются в основном частью реализации. Думая о них как свойствах, а не о полях, я могу лучше подумать о моем дизайне, что приводит к улучшению кода.
О, и я иногда получал выгоду от несовпадения исходной совместимости, возможности установки контрольных точек, доступа к журналу и т.д.
Ответ 6
Гораздо проще отладить проблему, связанную с полем, если она обернута аксессуаром свойства. Размещение точек останова в аксессуре может довольно быстро помочь в поиске повторного входа и других проблем, которые в противном случае могли бы не быть пойманы. Марширируя весь доступ к полю через аксессуар, вы можете точно определить, кто и что изменит.
Ответ 7
В .NET, по моему мнению, вы не можете привязывать данные к публичным полям; но только к свойствам. Таким образом, если вы хотите сделать привязку данных, у вас нет выбора.
Ответ 8
У меня когда-то были поля, которые я хотел бы выставить из окон из проекта, которые позволили получить статистику для программы (TotalItems и SuccessfulItems).
Позже я решил отобразить статистику в форме и смог добавить вызов в сеттер, который обновил отображение при изменении свойства.
Ответ 9
Очевидно, что если вы не создаете общую библиотеку классов, и вы не используете DataBinding, то использование поля не вызовет у вас никаких проблем.
Но если вы создаете общую библиотеку классов, вы будете глупыми ИМХО делать иначе, чем следовать рекомендациям по трем причинам:
-
пользователи вашей общей библиотеки классов могут захотеть использовать DataBinding.
-
потребители вашего общего класса могут иметь двоичную совместимость, что невозможно, если вы переключитесь с поля на свойство.
-
Принцип наименьшего удивления подразумевает, что вы должны быть совместимы с другими библиотеками общих классов, включая сам .NET Framework.
Ответ 10
ИМХО нет такой вещи, как тривиальное свойство, как люди их называли. Благодаря тому, как такие вещи, как работа по привязке данных, Microsoft подразумевает, что любой бит данных, являющийся частью открытого интерфейса объекта, должен быть свойством. Я не думаю, что они имели в виду, что это просто соглашение, подобное тому, которое есть в некоторых других языках, где синтаксис свойств больше связан с конвенцией и удобством.
Более интересным может быть вопрос: "Когда я должен использовать публичное поле вместо свойства" или "Когда есть публичное поле, а не публичное свойство, спасло ваш бекон?"
Ответ 11
Поля, которые относятся к типам структур, допускают прямой доступ к его членам, а свойства таких типов - нет. Следовательно, если Thing.Boz
было полем типа Point
, код, который хочет изменить его значение X
, мог бы просто сказать Thing.Boz.X += 5;
; если Thing.Boz
является изменяемым свойством, необходимо использовать var tmp = Thing.Boz; tmp.X += 5; Thing.Boz = tmp;
. Способность писать вещи более чисто с открытым полем часто , но не всегда, благо.
Если для Boz
всегда возможно быть полем, то изменение его членов напрямую будет более чистым, быстрым и лучше, чем копирование его во временную переменную, изменение этого и его копирование. Если тип Boz
предоставляет свои изменяемые поля напрямую (как структуры), а не обертывает их в тривиальные обертки, также возможно использовать на них такие вещи, как методы Interlocked
, что просто невозможно с помощью свойств. Там действительно только один недостаток использования полей таким образом: если когда-либо понадобилось заменить поле свойством, код, который полагался бы на предмет, являющийся полем, сломается, и может быть трудно исправить.
Короче говоря, я бы сказал, что в тех случаях, когда никто не обеспокоен возможностью обмена в разных версиях кода без необходимости перекомпилировать любых потребителей, наибольший эффект использования свойств, а не полей, заключается в том, чтобы запретить потребителям код от написания кода, который будет использовать (и полагаться) семантику открытых полей, которые имеют типы структуры.
Кстати, альтернативой экспонированию поля типа структуры было бы выставить метод ActOnXXX
. Например:
delegate void ActionByRef<T1>(ref T1 p1);
delegate void ActionByRef<T1,T2>(ref T1 p1, ref T2 p2);
delegate void ActionByRef<T1,T2,T3>(ref T1 p1, ref T2 p2, ref T3 p3);
// Method within the type that defines property `Boz`
void ActOnBoz<T1>(ActionByRef<Point, T1> proc, ref T1 p1)
{
proc(ref _Boz, ref p1); // _Boz is the private backing field
}
Код, который хотел добавить некоторую локальную переменную q
в Thing.Boz.X
, мог вызвать Thing.ActOnBoz((ref Point pt, ref int x) => {pt.X += x;}, ref q);
и выполнить действие непосредственно на Thing._Boz
, даже если поле не отображается.