For example, in an MVC app, I can use the Html helpers to create a label like this:
@Html.LabelFor(m => m.ProductName)
I haven't declared the variable "m" anywhere, but the ID开发者_开发问答E automatically figures out what I'm trying to do. It's somewhat disconcerting that the IDE knows more about my code than I do. I'd like to fix that.
I mostly want to know how it knows how to reference my model.
EDIT: Thanks for all of the answers.
So, "Html" is an instance of HtmlHelper. "Html" is a member of the ViewPage base class. Its value is set in the InitHelpers() method of the ViewPage base class. The HtmlHelper constructor takes the ViewContext of the ViewPage as a paramter. The ViewContext knows what model I'm using. The LabelFor is an extension method on the HtmlHelper class. And that's why the lambda expression knows how to reference my model.
Dots are connected. Thanks!
You need to read up on lambdas, but what's going on is that you're passing in a function pointer to the LabelFor
method. Because Html
is strongly typed (HtmlHelper<TYourModelType>
) and LabelFor
is declared like Func<TYourModelType, TValue>
, the compiler (and IDE) can determine that m
is an instance of your model type, and hence provide nice IDE drop downs for the members.
Sometimes people find it helpful to compare the other syntactical options at your disposal. For example, this would be equally valid:
Html.LabelFor(SomePropertyMethod);
...
string SomePropertyMethod(TYourModelType model)
{
return model.SomeProperty;
}
That is declared against your View at the top.
<%@ Page Inherits="System.Web.Mvc.ViewPage<MvcApplication1.Models.EntryForm1>" %>
So your form inherits from ViewPage and it would understand what type T is.
The generic parameter for LabelFor is the same type as your model:
Inherits="System.Web.Mvc.ViewPage<MyModel>"
The parameter for LabelFor is of type:
Expression<Func<MyModel,TValue>>
So the compiler knows that you'll be passing in a MyModel object into the lambda.
Apparently LabelFor takes a delegate whose signature has a single argument. The IDE sees this and based on that types m to have the same datatype as the argument.
The name m
doesn't stand for anything. @Html.LabelFor(n => n.ProductName)
means the same. It's an unary anonymous function that returns the ProductName of its argument.
m => m.ProductName
is a lambda representing an anonymous method which takes a single parameter, called m
. So m
is declared: right there in the lambda itself. The type should be inferrable by the compiler given the type of delegate LabelFor
takes as a parameter.
You have declared m
; what you've posted is lambda syntax (in expression form). The portion before the =>
is the parameter list for your lambda, and the portion after =>
is the body.
In your case, you're using an expression lambda. It's shorthand for:
@Html.LabelFor(m =>
{
return m.PropertyName;
});
In any case, the m
parameter here represents a value passed to the function.
精彩评论