Что я пытаюсь сделать
У меня есть веб-приложение, в котором у пользователя есть административный портал, который можно использовать для редактирования определенных настроек. Существует множество редактируемых настроек, поэтому я хотел бы создать единый набор наследуемых объектов MVC, чтобы я мог просто указать объект настроек (который представляет собой просто строку в таблице), и он будет отображать настройки, предлагать функции поиска , возможность добавлять/удалять записи и т.д.
Что у меня есть сейчас
Создан наследуемый объект контроллера. Он работает, беря тип объекта (например, объект User
) и создавая массив объектов AdminField
. Каждый представляет строку в базе данных. Производный класс контроллера также передает метаданные для каждого поля в виде флагов, поэтому код производного контроллера будет выглядеть следующим образом:
public class UserController : AdminBaseController<UserViewModel, User>
{
public UserController(Context context) :
base(context, new AdminField<User>[] {
new AdminField<User>(u => u.UserId, AdminFieldFlags.Hidden | AdminFieldFlags.IsID),
new AdminField<User>(u => u.UserName, AdminFieldFlags.Searchable | AdminFieldFlags.Sortable | AdminFieldFlags.Editable | AdminFieldFlags.EditLink, "User Name"),
new AdminField<User>(u => u.Password, AdminFieldFlags.Editable),
new AdminField<User>(u => u.AccessLevel, AdminFieldFlags.Editable)
}, "User")
{
}
}
Первый параметр — это лямбда, которая показывает, как получить указанное поле из объекта.
Вот сигнатура метода для конструктора AdminField
:
public AdminField(Expression<Func<TMaintainedType, object>> field, AdminFieldFlags flags, string displayName = null)
Данные поля также доступны для ViewModel, поэтому в представлении у нас есть такой код:
@foreach (var f in Model.Fields.Where(f => !f.Hidden))
{
//Gets original expression for this field
var expression = Model.ExpressionFromField<UserViewModel>(f);
<div class="form-group">
@Html.LabelFor(expression, new { @class = "control-label col-3" })
@Html.EditorFor(expression, new { htmlAttributes = new { @class = "form-control" } })
</div>
}
Виола! Метка поля и поле редактирования отображаются!
Проблема
Сигнатура метода для AdminField
принимает объект Expression<Func<TMaintainedType, object>>
. Это прекрасно работает для string
s, но (исходя из моего ограниченного понимания) вызывает упаковку/распаковку для int
полей, и, таким образом, сохраненное выражение изменяется с (например) u => u.UserId
на u => Convert(u.UserId)
. Поскольку я сохраняю массив полей, возвращаемый тип должен быть object
(поскольку он может отличаться), поэтому я не могу удалить Convert
.
В результате, когда поле захватывает выражение и поле равно int32
, я получаю ошибку System.InvalidOperationException
в строке LabelFor: Templates can be used only with field access, property access, single-dimension array index, or single-parameter custom indexer expressions.
Вопрос
Как я могу динамически преобразовать Expression<Func<T, object>>
в Expression<Func<T, int>>
?
В настоящее время я обхожу проблему, создавая специальный метод только для целых чисел, который удаляет преобразование, но это означает, что
- Мне нужно каждый раз проверять целое число (что делает МНОГО операторов If в представлениях), и
- Если мне нужен какой-либо другой тип значения, мне нужно будет создать еще один специальный метод и использовать операторы switch/if в представлениях, чтобы выбрать правильный метод.
Помощь! Дайте мне знать, если вам нужна дополнительная информация; всегда трудно понять, что включить.
Expression<Func<TMaintained, TReturn>>
- person The Bearded Llama   schedule 29.06.2016AdminField<T>
. Использование параметра типа возвращаемого значения потребует изменения его наAdminField<T, TReturn>
. Мне нужно иметь массивы объектовAdminField
с разными типами возврата, так что это не работает. Единственные альтернативы, которые я мог придумать (например, ковариация), будут работать только со ссылочными типами, а большинство моих типов являются типами значений. - person Daniel   schedule 29.06.2016HtmlHelper
без выражений (т.е.Html.Editor
вместоHtml.EditorFor
, что в основном просто дает мне бесплатную проверку MVC. Это не решает основную проблему, но обходной путь постепенно становится все меньше болезненный. - person Daniel   schedule 30.06.2016