1

Could anyone provide a clear (and easy to understand) explanation of what happens here (generally, generics, extension methods and Expression all together):

    public static MvcHtmlString TextBoxFor<TModel, TProperty>
        (this HtmlHelper<TModel> htmlHelper, 
              Expression<Func<TModel, TProperty>> expression)
    {
        return htmlHelper.TextBoxFor(expression, format: null);
    }

and further using of it here:

    Html.TextBoxFor(o => Model.SomeValue)

The most problematic moment for the understanding is the way how Expression parameter works in this conditions. I know how Generics work (generally he he) and I also know that this is an extension method (and how they also work), but can not catch how the expression then handled (or treated etc) in Html.TextBoxFor method (relatively to TModel and TProperty of Func).

The code provided is from ASP.NET MVC, but that's not about MVC at all: the question is only relatively to Expressions.

Thank you!

EDIT:

After some more investigations, there mostly the following question left: what is the role of TProperty class argument in the method definition provided and how is it influences the method calling?

Agat
  • 4,577
  • 2
  • 34
  • 62

3 Answers3

2

The first thing you should understand is that Expression<Func<...>> and Func<...> are essentially the same thing. In fact, the C# compiler can implicitly convert any Func literal into its equivalent Expression.

A Func<TModel, TProperty means "a delegate (function) that takes a TModel instance and returns a TProperty value". Leaving aside the whole expression tree magic, if you write:

Func<string, int> func = s => s.Length;

It is the same as writing:

Func<string, int> func = delegate(string s) { return s.Length; };

Which is also the same as writing:

int f(string s)
{
    return s.Length;
}

Func<string, int> func = f;

In other words, the first version, s => s.Length is just an anonymous version of the named function f in the last example. In C# this is called a Lambda Expression.

You could also write this:

Expression<Func<string, int>> expr = s => s.Length;

Notice that the syntax is exactly the same as before, we're just assigning it to an Expression<Func<string, int>> instead of a Func<string, int>. So, your question is, essentially, what does the Expression part do?

The best way to think of it is: Func<...> is a delegate that you can run, and is already compiled. Expression<Func<...>> is the same delegate before it's compiled. It's what the compiler sees. The above expression is a tree represented as:

Lambda
   |
   +----> Member Access
   |        |
   |        +-----> Parameter (Name: "s", Type: System.String)
   |        |
   |        +-----> Member (Property: System.String.Length)
   |
   +----> Parameter (Name: "s", Type: System.String)

This is what is formally referred to as an Abstract Syntax Tree. ASTs are what code looks like after it has been parsed but before it's been compiled. And indeed, every Expression actually has a Compile method that you can use to compile it into its corresponding executable Func type.

The reason to use an Expression<...> instead of a Func<...> is, generally, when you don't want the compiled version, at least not right away. Very often, in cases like this, you would use one because you want to just get the property name (e.g. Length in the example above) but you want to do so while maintaining all of the benefits of compile-time type safety, as opposed to using Reflection which could mysteriously break if some of the classes are changed.

In the specific case of the above, you could get the property name using the following code:

void Foo(Expression<Func<T, TResult>> expr)
{
    var member = ((MemberExpression)expr.Body).Member;
    var memberName = member.Name;
    // Do something with the member and/or name
}

Of course you could do dozens of different things at this point, so I won't try to get into any more detail - you can dig into the MVC source code for that. Also, the above example isn't production-ready code, since it makes an assumption that the expression is pure member access but it could be something more complicated, like s => s.Length + 1, and in that case the above method would fail. Expressions like this can also fail mysteriously when they're used in Linq or MVC, by the way.

Hopefully that answers your question. Delegates are a way of passing functions, whereas expressions are a way of passing code. You wouldn't normally need to write code involving Expression unless you are writing libraries or frameworks. But if you are writing libraries or frameworks, expression trees are a very powerful tool that are both much safer and potentially much more performant than old-fashioned Reflection.

Aaronaught
  • 120,909
  • 25
  • 266
  • 342
  • "In fact, the C# compiler can implicitly convert any Func into its equivalent Expression." - it never can. Only backward conversion is possible which is compilation. – LINQ2Vodka Nov 11 '13 at 04:06
  • 1
    @jim: What on earth are you talking about? There's a clear example *right below* that statement in this very answer. Try it yourself, you'll see that they all compile. Maybe I wasn't precise enough and should have said, `Func<...>` **literals** are implicitly convertible to `Expression>`. You can't convert a `Func<...>` *variable* to `Expression>` but I think the examples in this answer disambiguate pretty clearly. In other words, every lambda expression can be assigned to either a `Func<...>` or an `Expression>`. – Aaronaught Nov 11 '13 at 04:10
  • try compiling it: Func f = x => x; Expression> ex = f; – LINQ2Vodka Nov 11 '13 at 04:12
  • 1
    @jim: That's not what I meant, and I clearly explained that in my previous comment. I don't think you read it. If it makes you feel any better, I added one word to the answer which makes the statement 100% technically correct. – Aaronaught Nov 11 '13 at 04:13
  • They are equal absolutely different things (like table and a word "table") but sometimes user can think of it as of equal. C# compiler has no an idea how to implicilty convert Func to Expr. This was what you exactly saying. I dont argue with the entire text - you did it well excludin that line. – LINQ2Vodka Nov 11 '13 at 04:16
  • Thank you for your such explanative answer, however, I should say, that this is not fully what I am looking for. I've actually described, that I know the Expressions concept as well as I know how generics and action methods work. But the thing which I stuck here is in getting how all that work here together. The key thing is actually the line even from your code: `void Foo(Expression> expr)`. I don't really get how/why `T` and `TResult` do anything here. Why are there at all (if they even not used)? – Agat Nov 11 '13 at 10:11
  • Also, if functions can be convertible to expressions, the why I sometimes get some error message like "**Expression must return a value to render**" when my lambda is just like `MyMethod(v => Model)`? – Agat Nov 11 '13 at 10:14
  • +1: This is a good answer. My only comment is in relation to `Expressions like this can also fail mysteriously when they're used in Linq or MVC, by the way.`. As I've used similar code to your example without problems, I'd be interested to know if you have any more information on this. I've been searching around for a while now, but I can only find questions dealing with people not specifying the `@model` directive. – John H Nov 11 '13 at 15:16
  • Actually, the last my message with "Expression must return a value to render" was misunderstanding of VisualStudio design time error, which was related only to Razor parsing -- not `Expression` concept. So, that's not a thing. But still, the only stuff I don't get, what is the `TProperty` param: why is it in the TextBoxFor definition and how is it related to Exression in this case? Thanks. – Agat Nov 11 '13 at 15:49
  • it is introduced just in TextBoxFor and passes into Expression. It means if i call TextBoxFor then incoming expression must be of type. – LINQ2Vodka Nov 11 '13 at 15:57
  • @jim I've already answered to your similar comment bellow: you mixing up instance methods and extension methods. The example you've provided is related to the first situation. So, still hope, possibly @Aaronaught could bring some more light about `TProperty` in here. – Agat Nov 11 '13 at 16:27
  • 1
    @JohnH: Lots of expressions are invalid in libraries like Linq to SQL or Entity Framework because they need to be translated into SQL queries, and can't be. In Linq to Objects they'll always work. And of course MVC generally expects pure property expressions, you can't write `Html.TextBoxFor(x => x.FirstName + " " + x.LastName)`. – Aaronaught Nov 12 '13 at 01:28
  • @Aaronaught Oh ok, then in that case my code is fine. I appreciate you getting back to me. – John H Nov 12 '13 at 01:30
  • @Agat: I'm sorry but I don't understand your follow-up questions, and specifically I don't understand how they're not already answered here. It sounds like you're having some specific problem; I think you should ask a new question with more details (a **lot** more details). – Aaronaught Nov 12 '13 at 01:30
  • @Aaronaught Thank you for your efforts, but right, you thought that I was rather expecting general explanations about Generics and Expressions (in that case you would rather should have considered to mark the question as "duplicate"). But after a half of a day of explorations I've got to the point to answer on my question by my own. The core problem was in understanding how is the TProperty Type Template is related to the Expression and what it changes in the method provided logic (for instance, on calling). But, anyway, everything's now already clear. Thanks again for giving food to think on. – Agat Nov 12 '13 at 01:34
1

Type Expression<Func<TModel, TProperty>> is "an instruction what to do with the incoming object of type TModel to return some other object of type TProperty". Here:

public static MvcHtmlString TextBoxFor<TModel, TProperty>
    (this HtmlHelper<TModel> htmlHelper, 
          Expression<Func<TModel, TProperty>> expression)
{
    return htmlHelper.TextBoxFor(expression, format: null);
}  

the TextBoxFor extension method of HtmlHelper needs such paramenetr like desribed above, but the expression argument is of same type as HtmlHelper was created, i.e. some TModel, and it needs to return object of type TProperty.
The actual parameter m => m.SomeValue equals to "just return SomeValue property of the incoming m" but it could also be "return "foo"" or "return null" or "return new WeirdObject()".
Method TextBoxFor only calls an overload method.
UPDATE
Firstly, MSDN and google articles about "generic types" (like this and this) much better explain things than i could. Using this mechanism, you create classes or methods that are specific to type that was provided on instance creation so they are able for example to return the result of same type instead of general "object".
Say i want to create a List class (before Microsoft would do it) that can hold list of values of any type and also can return every second of them as result. I could do it like this:

public class List{
    public IEnumerable Items; // collection of "objects"
    public IEnumerable GetEvenItems(){
    // some implementation returning another "objects" collection
    }
}

You can use it to maintain list of ints, strings or genders or whatever, but GetEvenItems will always return you "objects" and you'll need to cast 'em back to the original type to continue work more speficically. Instead of this i make another class:

public class List<T>{ }

and by this saying "programmer must specify desired type so it's always known inside class and thus i can cast values to it anytime". As i know now the type, i can use it. For example:

public class List<T>{
    public T[] Items; // collection of strongly typed values
    public T[] GetEvenItems(){
        // some implementation returning typed collection
    }
}

By this i say that items now will be strongly of the specific type, that was provided on creation time. Also, my Item and GetEvenItems returns items of specific type as well so i can then operate on them as on colection of integers or strings. When outer code calls myList.GetEvenItems then it knows that the method will return array of T. By the way, instead of T you could use any other name, this is just a "type variable". You could put TModel or TMyThoughts instead of T in declaration.
I can also restrict possible types. Say my method DoTheWebJob can operate with something that can only be of IController type. Then I provide an additional constraint:

public class MyClass<T> where T: IController
{
    public T[] Items;
    public void DoTheWebJob()
    {
        Items[0].Execute(null);
    }
}

that means the only IController descendands can be specified for my class. As my class body already "knows" that T is IController then i can easily call IController specific methods.
Also you can design your class or method so programmer will have to provide more than 1 type like this:

public class List<T1, T2>{ }

So far so good. Let go to

System.Web.Mvc.HtmlHelper<T>

This is just like our List<T>.: when creting the instance, programmer specifies the actual T value like this:

HtmlHelper<int> myHelper = new HtmlHelper<int>();

Lets say i wanna have my own helper that renders html tags.

public class MyHtmlHelper<T>
{
    public string RenderSpan(string name, object value)
    {
        return String.Format("<span id=\"{0}\">{1}</span>", name, value.ToString());
    }
}

It's cool and can render SPAN tag with name and value provided in params. So i can put anything and it'll give me a nice looking SPAN, i even dont need generics in class declaration at all.
Now i want modify my renderer so it sets SPAN's ID attribute as the name of the property of some object. Say i have Product object with the Id property. I wanna pass Product into renderer so it sets SPAN's ID="Id" and the inner html as Id's value (say 5). How my renderer can know the name of property Id? If i simply pass Product.Id, this will be just an integer value, renderer will have no idea what is this property name and won't be able to set SPAN ID=...
Well, the power of expressions will help us. Firstly: Func<T1, T2> is a delegate that accepts T1 typed parameter and returns T2 typed result. Expression<Func<T1, T2>> is an expression that describes the logic of delegate Func<T1, T2> - so it can be easily compiled into delegate itself but not backward.

Write this code:

internal class Program
{
    public class Entity
    {
        public int Id { get; set; }
    }
    private static void Main(string[] args)
    {
        Expression<Func<Entity, int>> fn = e => e.Id;
        // breakpoint here
    }
}

set a breakpoint and watch the fn.Body data type. It will be of PropertyExpression - in short, system parses e => e.Id as "take this property of the object", but not "return value of Id". Since now body "thinks" of this as of some object's property and able both to read its name and the value. Using expression like this we can make renderer know our property name so it can render SPAN.

public class MyHtmlHelper<T>
{
    public string RenderSpan(string name, object value)
    {
        return String.Format("<span name=\"{0}\">{1}</span>", name, value.ToString());
    }
    public string RenderSpan(System.Linq.Expressions.PropertyExpression pe)
    {
        // extract property name and value and render SPAN here

    }
    public string RenderSpan(Expression<Func<object, object>> expr)
    {
        // if specified expr was like x => x.Id then it will actually be parsed like PropertyExpression in above
    }
}

but we already have entity type T in class declaration and can use this type. So we can modify last method like:

public string RenderSpan(Expression<Func<T, object>> expr)
{
    // if specified expr was like x => x.Id then it will actually be parsed like PropertyExpression in above
}

That will mean if htmlHelper was created as of HtmlHelper<MyModel> type then RenderSpan will require Expression<Func<MyModel, object>> expression. ex: myModel => myModel.Id;. In cshtml files you try to create TextBoxFor and will see it requires the same type as @model was. This is because the actual html helper was implicitly created as new HtmlHelper<MyModel>(). Now, when RenderSpan knows the T is that type the HtmlHelper was created with, it can allow you to use T's properties in the right part of x => x.Id. It knows the T = Entity and you can say "x.Id". If expression were of object, object then you wouldnt able to do this. In Microsoft's declaration they use TModel instead of T to make you intuitively understand what's it about.
Okay, now in short:
1. You write @model MyModel in your cshtml
2. MVC creates an HtmlHelper<MyModel> helper
3. Since #2 the SpanFor or the TextBoxFor knows the expression incoming argument is of MyModel type, can operate with its properties and allows you to use it typed in the right part of expression
I am not sure why they need the second type parameter as TProperty, it could be just object. Probably it is propogated deeper in the TextBoxFor method.

LINQ2Vodka
  • 2,996
  • 2
  • 27
  • 47
  • Thank you for the answer. And I should say that I understand generally, what is expression. But I can not catch `` part: neither in the expression method definition part, nor in the expression parameter... – Agat Nov 11 '13 at 10:21
  • @Agat they came from HtmlHelper declaration. Btw, I updated answer. – LINQ2Vodka Nov 11 '13 at 15:25
  • Thanks for such an effort, and all that long explanation might be helpful for someone, who is not familiar neither with generics nor with expressions. But unfortunately (or happily) that's not me. As I've already mentioned before, I know all those things (including knowing how exactly MVC works). But the only thing here I still don't get (if to speak of my very first code on top: `TextBoxFor`) what is the TProperty and why is it in the extension method definitions, as well, why is it as a parameter to return in expression from the declaration. – Agat Nov 11 '13 at 15:44
  • You correctly touched that the html helper is created basically on TModel, but what's about TProperty? – Agat Nov 11 '13 at 15:44
  • @Agat i think it is just introduced in the TextBoxFor for possible use inside the implementation. TextBoxFor might run inner generic methods for specified property. – LINQ2Vodka Nov 11 '13 at 15:54
  • The thing is that the sample I've provided is the code from MVC sources, so it is as it is. And also considering, that this is just an extension method, all the usages we can see are by eyes. – Agat Nov 11 '13 at 16:06
  • @Agat these are different methods: `Html.TextBoxFor()` and `Html.TextBoxFor();`. I think the second (we use on cshtml) is calling the first providing it with the actual types. There sould be an overload of `Html.TextBoxFor()` that calls the generic. – LINQ2Vodka Nov 11 '13 at 16:21
  • Not sure if they are "different". `Html.TextBoxFor()` is an extension method. It has "kind of" Generic signature, but is called without passing type arguments explicitly (as it usually goes with instance methods). And if that had just TModel -- that would be completely typical, but I still don't getn the TProperty. – Agat Nov 11 '13 at 16:25
  • I use default navigation with Resharper to sources. But that still have no difference. The thing is still in the signature method, because that TProperty must influence the way the method is called -- so I can not understand how does it influence. (In other words, if there is no TProperty, for instance, would would be the difference). – Agat Nov 11 '13 at 16:36
  • Anyway, I guess, I got what is that about. Thank you very much for your time. I will +1 the answer as it gave me some food for further thinking, but I probably also should write my own answer to explain what I was exactly looking for and what did I found. Thanks again! – Agat Nov 11 '13 at 17:06
  • @Agat yes, please post your answer as well :) – LINQ2Vodka Nov 11 '13 at 17:08
  • Added the answer. Please, have a look. – Agat Nov 11 '13 at 19:49
1

So, learning by teaching. This is what our life is about. he he

The question initially appeared to clarify some specific things I was not clear about the code posted, but after all the investigations, I guess, there is a sense to share the whole understanding I've got about generics, extension methods and expressions (if they are used all together).

That is pretty "scarry", but from other hands is also so beautifully about C#, when such a simple call of the method:

Html.TextBoxFor(model => model.SomeValue)

hides inside itself such reach and "deep" declaration, like:

public static class InputExtensions
{
    public static MvcHtmlString TextBoxFor<TModel, TProperty>
        (this HtmlHelper<TModel> htmlHelper, 
         Expression<Func<TModel, TProperty>> expression)
    {
        string format = (string) null;
        return InputExtensions
                .TextBoxFor<TModel, TProperty>(htmlHelper, expression, format);
    }
}

The code provided is decompiled version received with "Go to Implementation" with Resharper using. (Actually, I have to use "Navigate To/Decompiled Sources" after upgrading to Resharper 8, but this is not a place to talk about here -- mentioning just in case).

So, I will just try to explain the whole general "anathomy" of such methods definition (at least, which I know about that).


Goal:

To have an extension method which would extend certain generic class and allow to manipulated that class data (in complile time: having all the bonuses of Intellisense and refactoring) dependently on what class has been passed as a type argument to mentioned generic class.

In real life explanation, I would describe as the following: we have a class Car (generic one), which is (generally) "suitable" for carrying different things like milk, cabbages, bycicles. But when we define something like Car<Milk>, then that car can carry milk only. Also, we consider that that class building already finished (we can not change it). However, we also want to buy some trailer, which would carry exactly the same product as already defined for some car, like having "CreateATrailer" method. The way we would be able to determine the type of a trailer we need is with the product (Milk in our case) measure units (as those are different for different products: litters, kilos, items). In this case, generic extension methods (possibly, with expressions using) are pretty handy. (That might be not an ideal real life example, but this is what came into my mind).

In short:

public static class InputExtensions
// ^^ this is where Extension Methods must be placed (inside of a static class)
{
    public static MvcHtmlString TextBoxFor<TModel, TProperty>
    //     ^^ they must also be static    ^^ here must be defined all the generic types
    //                                       which are involved withing the method

        (this HtmlHelper<TModel> htmlHelper, 
    //   ^^ the first parameter must have "this"
    //      this is a parameter which defines the type that the method operates on
    //      so, in this case, it must be some "HtmlHelper<TModel>" class instance

         Expression<Func<TModel, TProperty>> expression)
    //   ^^ the second parameter in the declaration, 
    //      but the first one which appears from caller side (the only one in this very case)
    {
        string format = (string) null;

        return InputExtensions.TextBoxFor<TModel, TProperty>
               (htmlHelper, expression, format);
        // or might also be (dependently if the types 
        //    can be resolved automatically by compiller (the explanation below))
        //    as follows:
        return InputExtensions.TextBoxFor
               (htmlHelper, expression, format);
    }
}

Deep diving:

I won't be duplicating all the detailed explanations of generics, extension methods and expressions (actually, initially it's called "expressions trees"), which are widely available via google and msdn. But will just be more focused on how that would all work together.

public static class InputExtensions

There is nothing specific about that. Just any static class. Its name mostly does not play any role.


    public static MvcHtmlString TextBoxFor<TModel, TProperty>

The method must be static.

If we don't use generics we ommit the <...> part completely. But if we do, we should specify there all the Types (Types Templates) which runtime types will be further either resolved by compiler automatically (dependently on parameters you would pass when you call the method), or must be defined explicitly, like someObject.OurExtensionMethod<string, int>.


        (this HtmlHelper<TModel> htmlHelper, 

"this" modifier must be placed next to the first parameter and this is actually the sign that the method is an extension.

htmlHelper parameter will be representing the object, on which we call the extension method. For easier understanding, it might be simply replaced with "@this" name like (this HtmlHelper<TModel> @this. The only difference is just that you obviously don't have an access to any private member(s) of the class (as opposite to being 'inside' of the class to extend).

here is just a common generic type prototype -- nothing specific. It could be anything we want. Even string, i.e. (this string @this,.


         Expression<Func<TModel, TProperty>> expression)

That's the trickiest part, as for me here.

So, if to speak of extension methods part, this will the first parameter which you would need to provide to the method on its call when extending some class.

As for Expression... We use it here to allow a user to pass some value, which further can be obtained (by the method inside) from an instance, which we provide to him. I.e., Func<TModel, TProperty> (which is generally the same as Expression<Func<TModel, TProperty>> (but not completely the same generally)) means, that on the method call we provide the user some ability to work with the type is the one that was used for our HtmlHelper instantiation as a Type parameter.

In other words, if we created an instance of Car<Milk> (Milk means TModel in our case), then then we provide the Milk type to the caller, like Html.TextBoxFor(ourKindOfMilkObject => ourKindOfMilkObject.MeasureUnits), for instance.

(I guess, that might be pretty tricky to catch for people who are not familiar much with expressions (or even Func/Action concepts), so I just expect that if you read this you already know what it is (at least, basically)).


The trickiest question here is with TProperty and why is it even needed in here.

Ok, how does it work:

  • first of all, there must be some type defined to return from Func (Exspression<Func>) statement. That might be also just object type if you don't really care of that much: Expression<Func<TModel, TProperty>> expression;
  • if you to use object instead (and don't use TProperty, but still leave it in the method name declaration), then TProperty runtime type becomes unresolved, and you should it resolve explicitly on the method call (which is obviously, has no sense in development);
  • if you leave it and have something like that as an expression to pass when calling the method: Html.TextBoxFor(model => model.SomeValue), the compiler resolves the TProperty type and you don't have to specify its type on the method call, otherwise you would have to do the following: Html.TextBoxFor<ATypeOfYourModel, string>(model => model.SomeValue) (string == TProperty in this case).
  • right after the runtime type for TProperty is resolved, you get the syntax highlighting in VisualStudio tooltip (or Resharper hints) as '(this HtmlHelper htmlHelper, Expression> expression)' instead.

  • the most important difference here also is that we can specify limitation of types which are available for using on TProperty Prototype (the "AND:" section below).


About the method calling, again. If we have our object as follows (for instance):

var html = new HtmlHelper<CustomModel>();
var car = new Car<Milk>();

then we must call our extension method this way:

html.TextBoxFor<CustomModel, string>(model => model.SomeValue);
car.AddATrailer<Milk,ParticularMeasureUnitsType>
             (theCarProduct => theCarProduct.MeasureUnits);

but if all the Generic Types Templates runtime types are resolved (which is in our case (because Car is know that created with Milk by its definition (new Car<Milk>()) and the expression Func return value type is also available from SomeValue type definition), then we simplify:

html.TextBoxFor(model => model.SomeValue);
car.AddATrailer(theCarProduct => theCarProduct.MeasureUnits);

AND:

Incredibly important thing about Generics is also that we can define limitations of which class/interface can be used for the Generic Types Templates to use, with using a keyword where, like:

(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression)
        where TModel : CustomModel where some : ParticularValueType

Otherwise, if we use object instead of TProperty, we would not be able to control what we can and what we can not pass into the method (the same way, on which methods to allow the extension methods calling and on which not to).


I believe, there are still might be some things to improve or correct in here, so, please give your comments on that -- I will be happy to modify the topic.

Agat
  • 4,577
  • 2
  • 34
  • 62