11

I'm trying to write a strongly typed helper which would be something like this:

Html.Lookup(x => x.FooId);

for now I have this:

public static MvcHtmlString Lookup<T,TReturn>(this HtmlHelper<T> html, Func<T, TReturn> expression)
{
     // get string "FooId" here
}

Anybody knows how to get this ?

Rey
  • 3,663
  • 3
  • 32
  • 55
Omu
  • 69,856
  • 92
  • 277
  • 407
  • possible duplicate of [Get the property, as a string, from an Expression>](http://stackoverflow.com/questions/2789504/get-the-property-as-a-string-from-an-expressionfunctmodel-tproperty) – David Pfeffer Sep 23 '10 at 13:28
  • 1
    Why are you reinventing `ViewData.ModelMetadata`? – Craig Stuntz Sep 23 '10 at 13:30
  • @Craig Stuntz I don't really get what you mean, I just want to create a strongly typed helper – Omu Sep 23 '10 at 13:31
  • You're creating a helper for functionality which already exists. It's not clear, from your question, what problem you're trying to solve by doing so. – Craig Stuntz Sep 23 '10 at 15:48
  • possible duplicate of [Get method name and type using lambda expression](http://stackoverflow.com/questions/273941/get-method-name-and-type-using-lambda-expression) – nawfal Apr 27 '13 at 12:58

4 Answers4

24
public static class ExpressionsExtractor
{
    public static string Lookup<T, TProp>(this HtmlHelper<T> html, Expression<Func<T, TProp>> expression)
    {
        var memberExpression = expression.Body as MemberExpression;

        if (memberExpression == null)
            return null;

        return memberExpression.Member.Name;
    }
}

You would then call it with:

var propName = Html.Lookup(x => x.FooId);
David Pfeffer
  • 38,869
  • 30
  • 127
  • 202
  • 1
    i think this should work, but it look like I've didn't declared my expression correctly or something cuz I can't use it the I wanted – Omu Sep 23 '10 at 13:14
  • `return memberExpression == null ? null : memberExpression.Member.Name;` – Zasz Nov 22 '11 at 06:16
  • 12
    This won't work with value types. With value type expression will be something along the '{x => Convert(x.Property)}'. You'll need to cast it to UnaryExpression and then cast its operand to MemberExpression. – slawek Apr 11 '13 at 08:13
  • @slawek thanks! been struggling with this for an hour – Sonic Soul Nov 22 '16 at 13:18
14

Yet another code.

public MvcHtmlString Lookup<T, TReturn>(this HtmlHelper<T> html, Expression<Func<T, TReturn>> expression)
{
  return MvcHtmlString.Create(ExpressionHelper.GetExpressionText(expression));
}

Use ExpressionHelper class. Func is delegate, Expression is generate ExpressionTree at compile time. Expression.Compile() return delegate, but Func don't get ExpressionTree at runtime.

takepara
  • 10,413
  • 3
  • 34
  • 31
8

Currently using this class when I need this functionality outside of web project where System.Web.Mvc reference shouldn't exist:

namespace Interreg.Domain{
  using System;
  using System.Linq.Expressions;
  public class PropertyName{
    public static string For<T>(
      Expression<Func<T,object>> expression){
      var body=expression.Body;
      return GetMemberName(body);
    }
    public static string For(
      Expression<Func<object>> expression){
      var body=expression.Body;
      return GetMemberName(body);
    }
    public static string GetMemberName(
      Expression expression){
      if(expression is MemberExpression){
        var memberExpression=(MemberExpression)expression;
        if(memberExpression.Expression.NodeType==
           ExpressionType.MemberAccess)
          return GetMemberName(memberExpression.Expression)+"."+memberExpression.Member.Name;
        return memberExpression.Member.Name;
      }
      if(expression is UnaryExpression){
        var unaryExpression=(UnaryExpression)expression;
        if(unaryExpression.NodeType!=ExpressionType.Convert)
          throw new Exception(string.Format("Cannot interpret member from {0}",expression));
        return GetMemberName(unaryExpression.Operand);
      }
      throw new Exception(string.Format("Could not determine member from {0}",expression));
    }
  }
}

Good thing about this one is - it does not lose dots when going deeper than just one level.

Arnis Lapsa
  • 45,880
  • 29
  • 115
  • 195
0

a bit late but I am posting a simple solution that's working for me in .Net 4. It has handling for value types on line 4

public PropertyInfo GetPropertyInfo<TSource>(Expression<Func<TSource, object>> propertyLambda) {
        var member = propertyLambda.Body as MemberExpression;
        if (member == null) {// value types return Convert(x.property) which can't be cast to MemberExpression
            var expression = propertyLambda.Body as UnaryExpression;
            member = expression.Operand as MemberExpression;
        }
        return member.Member as PropertyInfo;
    }
Sonic Soul
  • 23,855
  • 37
  • 130
  • 196