如何通过在剃刀助手中解析表达式来获取复杂(嵌套)属性的值?

时间:2019-04-04 17:07:07

标签: c# asp.net-mvc razor

我有一个用于显示树状视图下拉菜单的剃刀助手。 我试图使它类似于DropDownFor帮助程序,以便在视图中轻松且熟悉地使用。 除了DataBinder.Eval()之外,还可以解析通过表达式提供的模型属性的值吗?

以前,我可以使用PropertyInfo.GetValue方法来解决问题,但是在检索属性的值方面存在问题,该属性是我正在使用索引器进行教学的一个集合: model => model.SettingsModel.Categories[i].CategoryKey

public static ITreeViewDropdown<ITreeViewItem> TreeDropDownFor<TModel, TProperty, ITreeViewItem>(
            this HtmlHelper<TModel> html,
            Expression<Func<TModel, TProperty>> expression,
            IEnumerable<ITreeViewModel<ITreeViewItem>> tree,
            string optionLabel,
            object htmlAttributes = null)

        {
            if (expression == null)
            {
                throw new ArgumentNullException(nameof(expression));
            }

            TModel model = (TModel)html.ViewContext.ViewData.ModelMetadata.Model;

            var memberExpr = expression.Body as MemberExpression;
            if (memberExpr == null)
            {
                throw new ArgumentException($"Expected body of type '{typeof(MemberExpression).Name}' but received '{expression.Body.GetType().Name}'", nameof(expression));
            }

            MemberInfo propertyMember = memberExpr.Member;
            string propertyName = ExpressionHelper.GetExpressionText(expression);

            if (propertyMember.MemberType != MemberTypes.Property)
            {
                throw new MemberAccessException($"{propertyName} must be a property");
            }

            // An alternative is needed here
            var propertyValue = DataBinder.Eval(model, propertyName);

            return new TreeViewDropdown<ITreeViewItem>(html, tree, propertyName, propertyValue, optionLabel, htmlAttributes);
        }

以上解决方案目前可满足我的需求:

@Html.TreeViewDropdownFor(m => m.SettingsModel.Categories[i].CategoryKey, Model.CategoryTree, "Please Select")

但是我read认为Eval()方法可能很慢,我想以“正确”的方式进行操作,而且我想不出其他方法如何获得SettingsModel.Categories[i].CategoryKey的值。如果提供的表达式更简单,例如,我可以轻松获得所需的值。

m = > m.ProjectViewModel.CategoryKey,但不包含集合和索引器。

1 个答案:

答案 0 :(得分:0)

expression.Compile().Invoke(model)实际上得到正确的值。考虑到类型是通用的,我认为它不会比这更好的