3

I'm interested to understand how are implemented LabelFor, EditorFor... methods that accept lambda expressions in MVC.

Lets say I have a class Person and I want to print the name and the value of a property. How must be implemented Label() and Editor() methods?

  class Person
  {
     public int Id { get; set; }
  }

  void Label(Expression<Func<Person, int>> expression)
  {
     //...
  }

  void Editor(Expression<Func<Person, int>> expression)
  {
     //...
  }

  public void Test()
  {
     Person p = new Person
     {
        Id = 42
     };

     Label(x => x.Id );  // print "Id"
     Editor(x => x.Id); // print "42"

  }
albert
  • 1,493
  • 1
  • 15
  • 33

2 Answers2

2

This answer to a similar question gives an implementation of Label. The code's by Josh Smith in the PropertyObserver class of his MVVM foundation:

    private static string GetPropertyName
        (Expression<Func<TPropertySource, object>> expression)
    {
        var lambda = expression as LambdaExpression;
        MemberExpression memberExpression;
        if (lambda.Body is UnaryExpression)
        {
            var unaryExpression = lambda.Body as UnaryExpression;
            memberExpression = unaryExpression.Operand as MemberExpression;
        }
        else
        {
            memberExpression = lambda.Body as MemberExpression;
        }

        Debug.Assert(memberExpression != null, 
           "Please provide a lambda expression like 'n => n.PropertyName'");

        if (memberExpression != null)
        {
            var propertyInfo = memberExpression.Member as PropertyInfo;

            return propertyInfo.Name;
        }

        return null;
    }

It works by looking at the expression tree and checking for the name of the property in member expressions.


For Editor, you can use a similar strategy of looking through the Expression to find out what you need about the property. What exactly to do depends a lot on what info you want.

The specific way you asked it where all you want is the value of a property from a Person, you can simplify a lot. I also added a Person parameter, since you seem to want the value for a given person.

int Editor(Person person, Func<Person, int> expression)
{
    return expression(person);
}

This can be used like Editor(p, p => p.Id);. Note that I changed Expression<Func<Person, int>> to Func<Person, int>, which means that instead of an expression tree it gets a Func. You can't examine a Func to find names of properties and such, but you can still use it to find the property from the Person.

Community
  • 1
  • 1
31eee384
  • 2,748
  • 2
  • 18
  • 27
  • You should mention that you took a bit of a shortcut with the `Editor` method by taking a `Func<>` instead of an expression tree. In MVC, they need information about the property *in addition to* the value, so they parse the expression tree and use reflection to determine the value. – StriplingWarrior Aug 31 '15 at 21:45
  • 1
    @StriplingWarrior Good call, edited. Had to be quick, let me know (or propose an edit) if there's something more. Thanks! – 31eee384 Aug 31 '15 at 21:57
-2
void Label(Expression<Func<Person, int>> expression)
{
    Person myPerson = new Person { Id = 42 };
    foreach (PropertyInfo prop in typeof(Person).GetProperties())
        if(prop.Equals(expression(myPerson))) print(prop.Name);
}

void Editor(Expression<Func<Person, int>> expression)
{
    Person myPerson = new Person { Id = 42 };
    print(expression(myPerson));
}
maraaaaaaaa
  • 7,749
  • 2
  • 22
  • 37
  • No, dude. You don't loop through all the properties for the class. And notice how you hard-coded "Person" as the model type.. Are you going to write one of these for every class? No, just no. The lamda expression already has the property's name. See @31eee384 's answer. – Daryl Aug 31 '15 at 21:16
  • @Daryl He hardcoded `Person` into the `delegate`, so it was safe for me to assume i can re use an existing `Type` according to OP's question. And by the way your treading on ground that is far away from the original question, he doesnt even know the basics of the `delegate` expression. He provided the lambda, and wanted to know how it would be implemented. That is all. – maraaaaaaaa Aug 31 '15 at 21:24
  • I think what clarified the question for me was this part of the Q: "I'm interested to understand how are implemented LabelFor, EditorFor... methods that accept lambda expressions in MVC." I think the asker was just simplifying the question by not using generics. – 31eee384 Aug 31 '15 at 21:33
  • 2
    @Andrew: This code won't work the way you think it will. You can't call `expression(myPerson)` like that, and even if you did, `prop.Equals()` on that would always return false. – StriplingWarrior Aug 31 '15 at 22:00
  • Care to explain why i cant call the expression ´like that´ – maraaaaaaaa Aug 31 '15 at 22:08
  • Does [this ideone example of the compiler error that results](http://ideone.com/fHuRsS) clarify? It's syntactically invalid--you can compile it to turn it into a delegate though. – 31eee384 Sep 01 '15 at 02:40