Есть ли причина, по которой связыватель моделей по умолчанию не привязывается к полям?
Я использую 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 и т. Д.
Надеюсь, это объясняет большую часть этого.