Reputation: 3952
While trying to understand TextBoxFor()
I came across this definition in MSDN....
TextBoxFor<TModel, TProperty>(HtmlHelper<TModel>, Expression<Func<TModel, TProperty>>, IDictionary<String, Object>)
Is this just a generic class, or is it somethign else, or is it non-c# ?
(The angular brackets within angular brackets is throwing me of)
And how do you interpret it (a link would be fine - as long as its ok for beginners to C# etc).
Upvotes: 1
Views: 1140
Reputation: 7449
A class with nested generic type parameters.
The inner part:
Func<TModel, TProperty>
A delegate, referencing ("describing") a function that takes the generic type TModel
as an argument and returns a result of generic type TProperty
, e.g.:
TProperty MyFunc(TModel model)
... which corresponds to the types in the usual argument to TextBoxFor()
:
model => model.Name
model
is of type TModel
and model.Name
is of type TProperty
.
The outer part:
Expression<T>
An expression tree describing a lambda expression (delegate) of the type T
. The Expression<T>
generic class allows you to (in simplified terms) examine the code itself at runtime rather than the result of executing it. In other words, the TextBoxFor()
method can e.g. extract the actual name of the property (Name
in the above example), in addition to compiling the expression and executing it to get the result.
If we simply took a Func<>
as an argument, we would only be able to call the passed delegate and get the result of that call, rather than examining it in this kind of detail.
For the HTML helpers, the use of expression trees is mainly a type safe alternative to the TextBox()
methods, which take the name of the property as a string.
So, in combination:
Expression<Func<TModel, TProperty>>
A parameter to TextBoxFor()
that is "An expression tree describing: a lambda expression that takes a parameter of the generic type TModel
and returns a property of the generic type TProperty
".
The nested generics aren't limited to something as relatively advanced as expression trees. A simpler, concrete, example of nested generics is this:
Dictionary<string, List<int>>
A dictionary with string
s for keys, and List
s of int
s as values.
Upvotes: 1
Reputation: 12681
It's a class.
Expression<Func<TModel, TProperty>>
encapsulates Func<TModel, TProperty>
, and contains extra metadata which can be used by third parties to rebuild the Func
in their own native language.
Func<TSrc, TDest>
represents a function that takes TSrc
as its input, and generates an instance of TDest
as its output. For example, I can say:
var addOne = new Func<int, int>(i => i + 1);
and addOne
would be a mapping that takes an integer and gives back that integer plus one. After you've defined it, you can then call addOne(1)
, and you'd expect that to give you 2.
The thing inside the brackets -- the i => i + 1 -- is a piece of syntax called a lambda. Confusingly, a lambda can be used to represent both a Func<TSrc, TDest>
and an Expression<Func<TSrc, TDest>>
. That is, depending on the context,
i => i + 1
represents either a Func<int, int>
object or an Expression<Func<int, int>>
object. This is an example (my favourite example) of homoiconicity in a language. That is, a syntax in which you can have objects of different classes represented by the same symbol, or icon.
Going back to MVC, the reason it wants an Expression<Func<TModel, TProperty>>
rather than just a plan old Func<TModel, TProperty>
is because it wants to know more about the property than what that property does with the model instance: it wants to know extra data such as the property name, its attributes, and what kind of error handling it uses. So you can give it something like
@Html.TextBoxFor(m => m.FirstName, ...)
and MVC will look up the property FirstName
in your model and build up all sorts of HTML based on the attributes you've defined on that property.
That's more or less how it works.
Upvotes: 2
Reputation: 15404
It's just a nested generic type.
An Expression
of type Func
of type TModel, TProperty
Upvotes: 2
Reputation: 887767
This is an example of nested generic type parameters.
Expression<T>
is an open generic class that takes a single type parameter.
Func<TModel, TProperty>
is a concrete generic delegate type that references type parameters from the surrounding generic function.
Upvotes: 3