53

I’m fairly new at C# and MVC and have used lambdas on certain occasions, such as for anonymous methods and on LINQ.

Usually I see lambda expressions that look something like this:

(x => x.Name), (x => { Console.WriteLine(x))

I understand that lambda = "goes to". I have never seen a lambda expression where the left parameter is not used.

I don’t know how to translate this lambda expression though

@Html.DisplayFor(modelItem => item.FirstName)

Can anyone shed some light on this one for me? Shouldn’t this be

(modelItem => modelItem.FirstName)?

I got this from Microsoft's Introduction to ASP.NET MVC tutorial.

tchrist
  • 78,834
  • 30
  • 123
  • 180
Jan Carlo Viray
  • 11,856
  • 11
  • 42
  • 63
  • Have you tested that implementation? Does it work? It would be nice to use the dot notation in that manner, I was under the impression it could only be accessed through indices. – Travis J Apr 10 '12 at 23:50
  • yeah, it's what I see tutorials show and have been doing it myself for a while. I've always wondered though, why not modelItem => modelItem.FirstName... tried that too and didn't work. Yes, it would be a lot better to use dot-notation. It seems like a "hack" to me in a way. I hope dot-notation would be possible in the future.. – Jan Carlo Viray Apr 11 '12 at 00:00
  • According to `GraemeMiller`'s link, a more proper way would be `@Html.DisplayFor( () => item.FirstName)` – Travis J Apr 11 '12 at 00:02
  • Yes I agree. It's much less confusing to have that instead. – Jan Carlo Viray Apr 11 '12 at 00:03

4 Answers4

103

A lambda expression is a way to write an anonymous function, i.e. a function without a name. What you have on the left side of the "arrow" are the function parameters, and what you have on the right side are the function body. Thus, (x => x.Name) logically translates to something like string Function(Data x) { return x.Name } the types string and Data will obviously vary and be derived from the context.

The absence of the left-side parameter translates into a function without parameters, so that this (() => someVariable) logically translates to this: string Function() { return someVariable; }

At this point you might start wondering, where someVariable comes from, it's not a function parameter and it is not defined in the function. You would be correct, a function like this would never compile. However the lambda function like this is perfectly fine, as it allows outer-scope variables be lifted and used this way. (Internally a wrapper class is created where the variables that are used in the lambda expression become fields.)

Now let's see what model => item.FirstName means. Logically it would translate to string Function(Model model) { return item.FirstName; }. Basically this is a function with a parameter, but this parameter is not used.

And now, the last bit of the information. Although lambda expressions represent functions in the end, sometimes they are created not with the purpose of actually being executed (although potentially they can). A lambda expression can be represented in the form of an expression tree. This means that instead of executing it it can be parsed.

In this particular case the MVC engine does not run the function that the lambda expression represents. Instead the expression is parsed so that MVC engine knows what html to emit for this particular line. If your data item does not come from your model object directly, the left part of the lambda expression does not matter.

niico
  • 11,206
  • 23
  • 78
  • 161
Andrew Savinykh
  • 25,351
  • 17
  • 103
  • 158
  • Great explanation. My answer should certainly be unchecked for this well written one :) – GraemeMiller Apr 11 '12 at 00:27
  • @GraemeMiller yeah I think this guy deserves a lot of credit and respect for his hard work. Thanks. Definitely a very beautiful answer regarding lambda, MVC engine, and parameterless lambdas in general :) – Jan Carlo Viray Apr 11 '12 at 01:13
  • 3
    @zespri Thanks a lot for the answer. Definitely a thorough one and answered my unconscious curiosities about lambdas and the mvc engine :) – Jan Carlo Viray Apr 11 '12 at 01:15
  • "However the lamda function like this is perfectly fine, as it allows outer-scope variables be lifted and used this way. (Internally a wrapper class is created where the variables that are used in the lambda expression become fields)" is particularly useful. Somewhat analogous to closures in JavaScript. Thanks for the great answer. – Joel Anair May 23 '13 at 17:58
  • great answer , but I think you are incorrect when you say "a function like that will never compile" If the function is a class member and so is somevariable, anyways i gave u an upvote – Mohit Shah Jan 31 '16 at 10:51
  • if the big heads at MSFT would have used @Html.DisplayFor(noParam => item.FirstName) that could have been self explanatory! No more hunting for the inexistent modelItem – dmihailescu May 24 '21 at 19:25
7

i think it's about the foreach loop. example:

@foreach(var item in model) 
{ 
 <td> 
     @html.displayfor(model => item.firstName) </td>
 </td>     
}

var item needs to be used because each item in the sequence is an anonymous type. model => item.firstName means (input parameter) => expression. you can't use the input parameter because we store the current "item" in item.

varg
  • 3,446
  • 1
  • 15
  • 17
  • Thanks! After reading the main answer (beautiful but pretty abstract), this helped clarify it in a more practical way for my novice brain :-) – Methodician Dec 29 '15 at 18:56
5

It is using a parameterless lambada. See this question

Basically DisplayFor doesn't use the lambda function parameter model (it could be anything I'd say use _ or ()) and just uses the lambda function within the for loop to use displayfor against it. DisplayFor requires a lambda function.

Community
  • 1
  • 1
GraemeMiller
  • 11,973
  • 8
  • 57
  • 111
1

I also struggled a lot to understand the codes generated by Visual Studio. Instead of providing a general explanation about lambda expression, I would like to put a context using ASP.NET MVC framework.

Suppose we prepared a Model class (e.g. Destination) with 2 attributes: City and ProvinceCode.

public class Destination
{
    public string City { get; set; }
    public string ProvinceCode { get; set; }
}

After generating the Controller and View, we should get the generated codes by Visual Studio as mentioned. Yet, the generated codes are somewhat hard to understand, especially for the data rows

@Html.DisplayFor(modelItem => item.City)

I just guess that the MVC team should think that Html helper class should be consistently used in the cshtml file. Thus, they tried to use tricks to pass the C# compiler. In this case, modelItem is not even used as an input parameter of this lambda expression. We can't use () as the type is NOT correct. That is why, if we replace model or any model object, the lambda expression works.

To be honest, I would like to rewrite the generated codes in a more readable form. Instead of using the Html helper class, we can simply render the correct output as follows:

@foreach (var item in Model) {
<tr>        
    <td>  
        @* Code Generated by Visual Studio. modelItem is a dummy param *@
        @Html.DisplayFor(modelItem => item.City)
    </td>
    <td>
        @* A better way - simply get rid of Html helper class *@
        @item.ProvinceCode
    </td>
</tr>
}
Peter Chung
  • 71
  • 1
  • 4
  • Yes, it would be nice to have the option to exclude DisplayFor. I'd also like to have the option to exclude linebreaks, so it could generate compact code when there are a lot of cells, like... @item.ProvinceCode – KevinVictor Oct 11 '18 at 16:26