Suppose you have a model like so:
class Foo
{
public int A {get; set;}
public int B {get; set;}
}
class SomeModel
{
public List<Foo> Foos { get; set; }
}
In a razor view on the ASP.NET mvc framework, you can do the following:
@model SomeModel
@for(int i = 0; i < Model.Foos.Count; ++i)
{
Html.EditorFor(x => x.Foos[i]);
}
And the razor engine will happily spit out the correct html containing the index, and will call the editor template with the correct indexed instance.
The EditorFor
method is a static extension method with the signature
public static MvcHtmlString EditorFor<TModel, TValue>(
this HtmlHelper<TModel> html,
Expression<Func<TModel, TValue>> expression
)
From the signature, it is clear that it is simply taking an expression, and the only context is coming from the HtmlHelper instance.
I have done very limited Expression
tree processing, but from what I have seen, I can't see any way that this static method could know the information that it is somehow magically getting.
How can the EditorFor
method figure out the index for generating html names and get the correct instance to pass to the editor template?
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.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.