Есть ли причина, по которой связыватель моделей по умолчанию не привязывается к полям?

Я использую ASP.NET MVC3, и мне интересно, что связыватель моделей по умолчанию привязывается к публичным свойствам, но не к публичным полям.

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

Вопрос: в чем причина?

3 ответа

но иногда я использую некоторые предопределенные классы, которые содержат некоторые поля

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

Итак, вернемся к основному вопросу: поля должны быть изменены только внутри данного класса. Они не должны быть доступны непосредственно снаружи. Они представляют и держат внутреннее состояние класса. Свойства, с другой стороны, - это то, что следует подвергать воздействию внешнего мира. Представьте, что в свойстве getter/setter у вас есть некоторая пользовательская логика. При непосредственном изменении поля эта пользовательская логика будет нарушена и может привести объект в несогласованное состояние.

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

Хотя я думаю, что Model Binder использует кеш для повышения производительности.

DefaultModelBinder предоставляет открытый метод: DefaultModelBinder.BindModel и ряд защищенных методов, доступных для переопределения. Все они перечислены здесь.

Помимо модели, эти методы относятся только к свойствам, а не к полям, таким как

  • GetModelProperties,
  • GetFilteredModelProperties,
  • GetPropertyValue,
  • OnXYZValidating,
  • OnXYZValidated,
  • OnXYZUpdating,
  • OnXYZUpdated,
  • GetXYZValue,

где XYZ означает либо Model, или же Property/ies, или оба, и так далее.

Как видите, нет Fields упоминается с этими именами вообще. Как пояснил Darin Dimitrov, Binder не допускает прямых изменений в состоянии модели. Отсюда нет Field в своих методах.

А также вы можете взглянуть на другой важный класс: ModelBindingContext. Экземпляр этого класса передается BindModel, и впоследствии BindSimpleModel, а также BindComplexModel, в зависимости от типа модели (string, int,... считаются простыми, все остальное сложно).

Итак, этот контекст имеет следующие свойства:

  • ModelXYZ, и
  • PropertyXYZ.

Другими словами, у вас нет средств для ссылки на поля в вашей ViewModel, если вы не переопределите эти классы и не предпримете специальные действия для этого.

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

РЕДАКТИРОВАТЬ: класс ModelMetadata содержит все данные, необходимые для привязки модели. Однако его код не показывает никаких признаков полей, имен полей и т. Д. Только на свойства ссылаются и обращаются к ним. Таким образом, даже если вы попытаетесь унаследовать и переопределить DefaultModelBinder и ModelBinderContext, вы все равно не сможете получить доступ к полям, не обращая внимания на то, что является их модификатором доступа: public, private и т. Д.

Надеюсь, это объясняет большую часть этого.

Другие вопросы по тегам