从另一个表达式构建索引表达式

Rap*_*aus 1 c# asp.net-mvc lambda expression-trees

脚本

public class Element {
   public int Id {get;set;}
}

public class ViewModel {
   public IList<Element> Elements{get;set;}
}
Run Code Online (Sandbox Code Playgroud)

我有一个类型参数的方法Expression<Func<Element, int>>,看起来像m => m.Id

我想改造

m => m.Id (其中m是元素)

x => x.Elements[0].Id 其中x是ViewModel,0是"index"参数

我现在拥有的(当然是通用的,为了清晰起见我删除了通用部分)

public static class Helpers {
    public static Expression<Func<ViewModel, int>> BuildExpressionArrayFromExpression(
                this Expression<Func<Element, int>> expression,
                ViewModel model,
                int index = 0, 
                string bindingPropertyName = "Elements"//the name of the "List" property in ViewModel class
                ) 
    {
       var parameter = Expression.Parameter(typeof(ViewModel), "x");
       var viewModelProperty = model.GetType().GetProperty(bindingPropertyName);
       Expression member = parameter;//x => x
       member = Expression.Property(member, viewModelProperty);//x => x.Elements

       var test1 =  Expression.Property(member, "Item", new Expression[]{Expression.Constant(index)});
       //x => x.Elements.Item[0], and I don't want Item

       var test2 = Expression.Call(member, viewModelProperty.PropertyType.GetMethod("get_Item"), new Expression[] {Expression.Constant(index)});
       //x 0> x.Elements.get_Item(0), and I don't want get_Item(0)

       //code to add Id property to expression, not problematic
       return Expression.Lambda<Func<ViewModel, int>(member, parameter);
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑

我需要x => x.Elements[0]而不是x => x.Elements.Item[0],因为必须用一个调用生成的表达式InputExtensions.TextBoxFor(<myIndexedExpression>)

想象一下这样的课程

public class Test {
  public int Id {get;set;}
  public IList<Element> Elements {get;set;}
}
Run Code Online (Sandbox Code Playgroud)

和一个邮政行动

[HttpPost]
public ActionResult Edit(Test model) {
 bla bla bla.
}
Run Code Online (Sandbox Code Playgroud)

如果我的输入的名称属性没有很好地生成,那么我有绑定问题(我的Post Action中的model.Elements为空).

我的输入的名称属性应该是

Elements[0]PropertyName
Run Code Online (Sandbox Code Playgroud)

我得到(取决于我的尝试)

PropertyName

或者(也许不确切,我试图重现这个案例)

Elements.Item[0].PropertyName
Run Code Online (Sandbox Code Playgroud)

EDIT2

还尝试了一个不同的解决方案,使用ViewData.TemplateInfo.HtmlFieldPrefix,但我得到了

Elements.[0].PropertyName
Run Code Online (Sandbox Code Playgroud)

(和Elements_ 0 _PropertyName为Id).

第一个点在名称中是不需要的,第一个"双下划线"应该是id中的简单点.

我实际上使用这个解决方案,使用正则表达式(argh)来删除不需要的东西.和_,但我想避免这种情况.

Jon*_*eet 6

只是表达式树的字符串表示问题,您无法更改它.你正在构建的表达式树很好.如果使用lambda表达式构建表达式树,则可以看到相同的效果:

using System;
using System.Collections.Generic;
using System.Linq.Expressions;

class Test
{
    public static void Main()
    {
        Expression<Func<List<string>, string>> expression = list => list[0];
        Console.WriteLine(expression);
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

list => list.get_Item(0)
Run Code Online (Sandbox Code Playgroud)

如果调用ToString()表达式树的结果确实是你面临的问题,我会感到非常惊讶.而不是告诉我们你认为你需要的结果和模糊的"我需要它以获得MVC绑定理由"的理由,你应该解释实际上出了什么问题.我强烈怀疑问题不在你想象的地方.