1

The answer of Marc Gravell in this post explains how to create expressions just like that:

var lambda = CreateExpression<SomeModel, bool>("IsAlive");

It's possible avoid the explicit type bool and that the method obtains the return type from "IsAlive" property?

Something like this:

var lambda = CreateExpression<SomeModel>("IsAlive");

And lambda will be a Expression<Func<SomeModel, bool>>.

And in:

var lambda = CreateExpression<SomeModel>("StringProperty");

lambda will be a Expression<Func<SomeModel, string>>.

Rafael León
  • 71
  • 1
  • 9
  • do you want to avoid explicit type for some reason ? If it is because you want to reuse that for different models which do not share any interface type, you might want to use dynamic maybe. But I am not quite sure if it would work – Gonzalo.- May 31 '18 at 16:28
  • I already try with dynamic but don't works. – Rafael León May 31 '18 at 16:36
  • The type is really needed here, otherwise how would you expect to use the returned expression? – DavidG May 31 '18 at 16:47
  • @DavidG That is exactly the problem you run into. Not sure it's a good approach but it was a fun learning exercise. – TheSoftwareJedi May 31 '18 at 17:09
  • @TheSoftwareJedi The point is that it's almost certainly not a good approach. You've already found out that you now have an expression that is weakly types (i.e. a `LamdaExpression` instead of `Expression`). – DavidG May 31 '18 at 17:12
  • @DavidG Agreed, that's what the answer demonstrates. – TheSoftwareJedi May 31 '18 at 17:28

1 Answers1

1

You can in fact do this, but the type becomes unknown. The object returned from this method will be of the proper type Expression<Func<Test, string>> but cannot be strong typed at compile time:

    static LambdaExpression CreateExpression<TModel>(string propertyName)
    {
        var t = typeof(TModel);
        var param = Expression.Parameter(typeof(TModel), "x");
        //get the type for the 2nd generic arg
        var propType = t.GetProperty(propertyName).PropertyType;
        //make the generic type Func<TModel, TProp>
        Type genericFuncType = typeof(Func<,>).MakeGenericType(new Type[] { typeof(TModel), propType });
        //get the Expression.Lambda method
        MethodInfo mi = typeof(Expression).GetMethods().First(a => a.Name == "Lambda" && a.GetParameters().Length == 2);
        //get the Expression.Lambda<Func<TModel, TProp>> method
        MethodInfo mi2 = mi.MakeGenericMethod(new Type[] { genericFuncType });
        //Call Expression.Lambda<Func<TModel, TProp>>
        return (LambdaExpression)mi2.Invoke(null, new object[] { Expression.PropertyOrField(param, propertyName), new ParameterExpression[] { param }});
    }

However note that the return type is now somewhat unknown and will need cast to use (or use dynamic).

So now you need even more code to cast it. Perhaps this would be useful in some sort of factory or such - not sure your use case.

class Program
{
    public static void Main(string[] args)
    {
        var theExpression = CreateExpression<Test>("Name");
        var theExpressionStrongType = theExpression as Expression<Func<Test, string>>;
        //now you could use theExpressionStrongType

        //or do this and go wild. :)
        dynamic d = theExpression;


        Console.ReadKey();
    }
}
class Test
{
    public string Name { get; set; }
}

Disclaimer: if you seriously want to use this in a production environment, I would clean up the code a LOT to just get refection types once, etc, etc...

TheSoftwareJedi
  • 34,421
  • 21
  • 109
  • 151