How to create Expression<Func<TModel, string>> expression from Property Name

asp.net-mvc, c#, lambda

Solution

It looks like you want to call `ModelMetadata.FromLambdaExpression`, not `FromStringExpression`. You can create an expression like

x => x.PropertyName

from scratch, like this:

// Get a reference to the property
var propertyInfo = ExpressionHelper.GetPropertyInfo<TModel>(propertyName);
var model = ExpressionHelper.Parameter<TModel>();

// Build the LINQ expression tree backwards:
// x.Prop
var key = ExpressionHelper.GetPropertyExpression(model, propertyInfo);
// x => x.Prop
var keySelector = ExpressionHelper.GetLambda(typeof(TModel), propertyInfo.PropertyType, model, key);

To make the code more readable, the nitty-gritty expression tree manipulation is moved into this helper class:

public static class ExpressionHelper
{
    private static readonly MethodInfo LambdaMethod = typeof(Expression)
        .GetMethods()
        .First(x => x.Name == "Lambda" && x.ContainsGenericParameters && x.GetParameters().Length == 2);

    private static MethodInfo GetLambdaFuncBuilder(Type source, Type dest)
    {
        var predicateType = typeof(Func<,>).MakeGenericType(source, dest);
        return LambdaMethod.MakeGenericMethod(predicateType);
    }

    public static PropertyInfo GetPropertyInfo<T>(string name)
        => typeof(T).GetProperties()
        .Single(p => p.Name == name);

    public static ParameterExpression Parameter<T>()
        => Expression.Parameter(typeof(T));

    public static MemberExpression GetPropertyExpression(ParameterExpression obj, PropertyInfo property)
        => Expression.Property(obj, property);

    public static LambdaExpression GetLambda<TSource, TDest>(ParameterExpression obj, Expression arg)
        => GetLambda(typeof(TSource), typeof(TDest), obj, arg);

    public static LambdaExpression GetLambda(Type source, Type dest, ParameterExpression obj, Expression arg)
    {
        var lambdaBuilder = GetLambdaFuncBuilder(source, dest);
        return (LambdaExpression)lambdaBuilder.Invoke(null, new object[] { arg, new[] { obj } });
    }
}

Building the expression tree from scratch gives you the most flexibility in creating the lambda expression. Depending on the target property type, it may not always be an `Expression<Func<TModel, string>>` - the last type could be an `int` or something else. This code will build the proper expression tree no matter the target property type.

Problem

My Html helper method looks like following ``` public static MvcHtmlString Control<TModel>(this MyHtmlHelper<TModel> helper, string propertyName, LayoutHelper layout, TemplateType templateType = TemplateType.Screen) { //... } ``` I want to convert my property name into following ``` Expression<Func<TModel, string>> expression ``` Any help will be much appreciated

Original source