6

假设你有一个这样的模型:

class Foo
{
    public int A {get; set;}
    public int B {get; set;}
}

class SomeModel
{
    public List<Foo> Foos { get; set; }

}

在 ASP.NET mvc 框架的 razor 视图中,您可以执行以下操作:

@model SomeModel

@for(int i = 0; i < Model.Foos.Count; ++i)
{
   Html.EditorFor(x => x.Foos[i]);
}

Razor 引擎会愉快地吐出包含索引的正确 html,并使用正确的索引实例调用编辑器模板。

EditorFor方法是带有签名的静态扩展方法

public static MvcHtmlString EditorFor<TModel, TValue>(
this HtmlHelper<TModel> html,
Expression<Func<TModel, TValue>> expression
)

从签名中可以清楚地看出,它只是采用一个表达式,唯一的上下文来自 HtmlHelper 实例。

我做了非常有限的Expression树处理,但从我所见,我看不出这个静态方法可以知道它以某种方式神奇地获得的信息的任何方式。

该方法如何EditorFor找出生成 html 名称的索引并获取正确的实例以传递给编辑器模板?

4

1 回答 1

6

You are passing it an expression, not the value of x.Foos[i]. MVC then evaluates that expression and figures out that you gave it a collection with an index. You would get the same result if you removed your entire loop and did:

Html.EditorFor(x => x.Foos)

MVC will then automatically render the editor template for all elements of the collection and generate proper names.

You can read more about how MVC handles display/editor templates here: Link

EDIT : To see this in action, here's a random piece of code I scribbled:

List<string> list = new List<string>() { "A", "B", "C" };
var tester = new ExpressionTester<List<string>>(list);
var item = tester.Foo(p => p[0]);

You'll also need this class:

public class ExpressionTester<TModel>
{
    private TModel _list;
    public ExpressionTester(TModel list)
    {
        _list = list;
    }

    public TValue Foo<TValue>(Expression<Func<TModel, TValue>> expression)
    {
        var func = expression.Compile();
        return func.Invoke(_list);
    }
}

Stick a breakpoint in Foo() and look at the parameter expression in debug. You'll find under Body -> Arguments the index you passed with the expression. Under Body -> Method you'll see that it is in fact a generic list.

于 2013-02-02T07:14:46.533 回答