首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >将表达式m => m.Name转换为m => m[index].Name

将表达式m => m.Name转换为m => m[index].Name
EN

Stack Overflow用户
提问于 2012-11-19 10:47:52
回答 2查看 400关注 0票数 0

给定一个Expression<Func<T, TValue>> (如m => m.Name)和一个index,我希望能够将表达式转换为m => m[index].Name)。我必须承认我被困在..。

如果你想要“为什么”(也许还能找到更好的方法),我会给你一个实际的场景。

场景:设想一个服务器端可编辑的网格(没有javascript)。

我用一个类似于这样的助手来构建网格:

代码语言:javascript
复制
@(Html.Grid(Model)
.Columns(columns => {
   columns.Edit(m => m.Name);
   columns.Edit(m => m.Code);
})
.AsEditable());

模型是一个IQueryable<T>

m => m.Name是一个Expression<Func<T, TValue>> (TValue是字符串)

m => m.Code是一个Expression<Func<T, TValue>> (TValue是int)

在呈现视图时,我希望显示一个html表单。枚举IQueryable<T> (顺序、分页)。=>好的

因此,我将有一个List<T>为5,10或20 T项目。

NameCode应该表示为TextBox,使用经典的HtmlHelper.TextBoxFor(Expression<Func<T, TValue>>) (创建HtmlHelper<T>没有问题)

但是,由于我有一个列表,如果我想要正确的模型绑定,我不能直接使用m => m.Name,而是应该使用m => m[indexOfItem in List<T>].Name

编辑:详细信息:

假设我们有一个实体类

代码语言:javascript
复制
public class Test {
  public int Id {get;set;}
  public string Name {get;set;}
  public string Code {get;set;}
}

然后,检索IQueryable<Test>的方法

然后看一看

代码语言:javascript
复制
@model IQueryable<Test>

@(Html.Grid(Model)
    .Columns(columns => {
       columns.Edit(m => m.Name);
       columns.Edit(m => m.Code);
    })
    .AsEditable());

正如您所看到的,作为参数的模型是IQueryable<Test>

代码语言:javascript
复制
m => m.Name

代码语言:javascript
复制
m => m.Code

只是模型的属性(我希望在网格中以TextBox的形式显示这些属性)。

该模型是一个IQueryable<T> (而不是IEnumerable<T>),因为网格管理排序和分页,所以我的控制器和服务层不需要知道分页和排序。

更清楚了吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-11-19 17:15:50

这可以很容易地通过编写自定义ExpressionVisitor来实现。

代码语言:javascript
复制
public static class ExpressionExtensions
{
    private class Visitor : ExpressionVisitor
    {
        private readonly int _index;
        public Visitor(int index)
        {
            _index = index;
        }

        protected override Expression VisitParameter(ParameterExpression node)
        {
            return Expression.ArrayIndex(GetArrayParameter(node), Expression.Constant(_index));
        }

        public ParameterExpression GetArrayParameter(ParameterExpression parameter)
        {
            var arrayType = parameter.Type.MakeArrayType();
            return Expression.Parameter(arrayType, parameter.Name);
        }
    }

    public static Expression<Func<T[], TValue>> BuildArrayFromExpression<T, TValue>(
        this Expression<Func<T, TValue>> expression,
        int index
    )
    {
        var visitor = new Visitor(index);
        var nexExpression = visitor.Visit(expression.Body);
        var parameter = visitor.GetArrayParameter(expression.Parameters.Single());
        return Expression.Lambda<Func<T[], TValue>>(nexExpression, parameter);
    }
}

然后您可以使用这样的扩展方法:

代码语言:javascript
复制
Expression<Func<Test, string>> ex = m => m.Code;
Expression<Func<Test[], string>> newEx = ex.BuildArrayFromExpression(1);
票数 1
EN

Stack Overflow用户

发布于 2012-11-19 13:49:46

好吧,有些东西(丑陋的,只是为了测试目的)起作用了,但它让事情变得不清楚,所以我会等待一个更好的解决方案,或者以另一种方式构建我的输入:

代码语言:javascript
复制
public static Expression<Func<T[], TValue>> BuildArrayFromExpression<T, TValue>(this Expression<Func<T, TValue>> expression, int index)
{
    var parameter = Expression.Parameter(typeof(T[]), "m");
    Expression body = Expression.ArrayIndex(parameter, Expression.Constant(index));
    var type = typeof(T);
    var properties = expression.Body.ToString().Split('.');//ugly shortcut for test only
    foreach (var property in properties.Skip(1))
    {
        var pi = type.GetProperty(property);
        body = Expression.Property(body, type.GetProperty(property));
        type = pi.PropertyType;
    }
    return Expression.Lambda<Func<T[], TValue>>(body, parameter);
}

在RenderMethod中使用,为List<T>的每一行调用(从IQueryable<T>返回的分页/ordered列表)

代码语言:javascript
复制
public override ... RenderContent(T dataItem) {
  var helper = new HtmlHelper<T[]>(GridModel.Context, new GridViewDataContainer<T[]>(GridModel.PaginatedItems.ToArray(), GridModel.Context.ViewData));
  var modifiedExpression = Expression.BuildArrayFromExpression(GridModel.PaginatedItems.IndexOf(dataItem));//GridModel.PaginatedItems is the List<T> returned when "executing" the IQueryable<T>
  var textBox = helper.TextBoxFor(modifiedExpression);
  ...
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/13452205

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档