简体   繁体   中英

Lambda expression in @Html.DisplayNameFor()

Let's say I am passing a List of Person as the model to a view page:

@model IEnumerable<Foo.Models.Person>

@foreach (var item in Model)
{
    <p>
        @Html.DisplayFor(ListOfPersons => item.Id) : @Html.DisplayFor(ListOfPersons =>item.Name)
    </p>    
}

I just don't get how this Lambda expression works. Why we are passing a IEnumerable and get a single value of on its objects?

As ListOfPersons is not a declared variable, and is just the parameter name for the expression, the expressions are valid.

To briefly touch on expressions, they are composed of both a parameter set and a body.

(parameter set) => (body)

The parameter set can be empty () or include 1 or many parameters (x) or (x,y) for example. The body then can use those parameters similar to how a method body would use parameters passed in.

@Html.DisplayFor(ListOfPersons => item.Id) when used in the scope shown is ignoring the parameter. It doesn't use it, and is similar to something like this

public int Id = 5;
public string DisplayFor(Person ListOfPersons)
{
    return Id;
}

So you can see from this aspect that the parameter is not used and the value returned is actually a value from a different scope.

DisplayFor is scoped to use the page's model to bind to. So regardless of the parameter name, what is passed in to the parameter is going to be the model. As such, since the parameter is being completely ignored here, it doesn't particularly matter what it was named and could simply be () or _ .

The returned value is then the value from the body, in this case item.Id and item.Name . However, as a result of there being no use of the parameter, the html rendered will be incorrect even though the value shown will be what looks to be accurate.

In order to remedy this, the model must be properly accessed or the rendered html will not be bound on post. This is typically done by iterating and using an index reference, as is shown in @Jonespolis' answer .

use a for loop in razor, so you maintain a direct reference to your model:

@for(int i =0; i < Model.Count(); i++)
{
   <p>
    @Html.DisplayFor(model => model[i].Id) : @Html.DisplayFor(model => model[i].Name)
   </p>    
}
 @Html.DisplayFor(ListOfPersons => item.Id) : @Html.DisplayFor(ListOfPersons =>item.Name) 

The view engine will examine the expression and determine that you want "display" controls for the Id and Name properties. It ignores the "input" variable name ( ListOfPersons * in this case) and the item variable and just parses the expression on the right. You could just as well have done this:

@Html.DisplayFor(_ => item.Id) : @Html.DisplayFor(_ => item.Name)

*Note that ListOfPersons in your lambda does NOT reference a local variable - it just creates a new "variable" that you could reference in your lambda. The fact that you seem to have a property or local variable named ListOfPersons is irrelevant.

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM