Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MVC 3: HTML.DisplayFor and the Lambda expression

I have found other topics regarding this, but none of them made me understand what I'm trying to figure out.

I am studying MVC 3 and I have problems wrapping my head around the Lambda expressions that go with @HTML.DisplayFor() in the scaffolding template.

I am working with the MvcMusicStore sample application, the view created by the scaffolding looks like this:

@model IEnumerable<MvcMusicStore.Models.Album>

...

@foreach (var item in Model) {
    <tr>
        <td>
            @Html.DisplayFor(modelItem => item.Genre.Name)
        </td>

I understand that DisplayFor is a extension method to HTML and that it takes an expression as a parameter. I researched Lambda expressions and understand them in other contexts such as with enumerable strings. For example:

cities.Where(s => s.StartsWith("L"));

What boggles my mind is, that in the second example, the first part of the expression (s) is actually used in the second part (s.startswith..), so it makes sense and I get what the program is doing with it. But this is not the case in the MVC 3 view. modelItem is not beeing used anywhere. I tried renaming just "modelItem" to whatever like so:

@Html.DisplayFor(iAmWearingShortPantsToday => item.Genre.Name)

This code works just as well, displaying all the items and values correctly. This makes me doubt that in this case "modelItem" is actually used for anything. But then, why is it there?

I have also tried to translate this Lambda expression into a delegate (which I believe it is the short form for), like this:

@(Html.DisplayFor(delegate(IEnumerable<MvcMusicStore.Models.Album> modelItem) { return item.Genre.Name; }))

This however, does not work. The resulting error is:

CS1946: An anonymous method expression cannot be converted to an expression tree

Hence my question:

What is "modelItem" good for? What does HTML.DisplayFor() do with modelItem? Are there other cases maybe, where this first part of the expression becomes significant?

If it's possible to translate this expression into a proper delegate, that might also help me to understand what's exactly going on.

Thanks very much

like image 621
Alexander Rechsteiner Avatar asked Nov 03 '22 19:11

Alexander Rechsteiner


1 Answers

I understand your confusion. Actually modelItem variable is never used in the lambda expression. What is used is the item variable which is captured in a closure from the outer context. The item variable is simply the local variable defined in the foreach loop.

By the way when you see an expression like modelItem => item.Genre.Name in ASP.NET MVC view, that's usually a sign for a bad coding practice. Avoid it. The internet is swarming with such bad examples. Really. I am sick of seeing this. Please help me eradicate this practice.

Here's an alternative method in which the variable is actually used:

@model IList<MvcMusicStore.Models.Album>
...

@for (var i = 0; i < Model.Count; i++) {
    <tr>
        <td>
            @Html.DisplayFor(x => x[i].Genre.Name)
        </td>
        ...
    </tr>
}

And even better. Why write loops at all? When we can directly use editor/display templates:

@model IEnumerable<MvcMusicStore.Models.Album>
...
@Html.DisplayForModel()

and then define a display template that will automatically be rendered by ASP.NET MVC for each element of the model collection (~/Views/Shared/DisplayTemplates/Album.cshtml)

@model Album
<tr>
    <td>
        @Html.DisplayFor(x => x.Genre.Name)
    </td>
    ...
</tr>
like image 77
Darin Dimitrov Avatar answered Nov 09 '22 03:11

Darin Dimitrov