Search code examples
c#.netexpressionexpression-trees

How can I build an expression that compiles to a Func<T>?


Suppose I have a static method that returns T such as:

T myT = MyClass.Create(type); // type is System.Type

I then want to be able to build and compile an expression so that I can have a Func<T> but I cannot figure out how to do it.

I can build it for a Constant doing:

Func<T> result = Expression.Lambda<Func<T>>(Expression.Constant(string.Empty)).Compile()

but for MyClass.Create(type) I am stuck.

Func<T> result = ....?

Solution

  • Thanks to the tip from usr I managed to do it using Expression.Call so given:

    public static class MyClass
    {
        public static string GetTime() 
        {
            return DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss,fff");
        }
    
        public static string GetName(Type type)
        {
            return type.Name;
        }
    }
    

    Then:

    // Calls static method GetTime with no args
    var mCallGetTime = Expression.Call(typeof(MyClass), "GetTime", null);
    Func<string> resultNoArg = Expression.Lambda<Func<string>>(mCallGetTime).Compile();
    
    // The input param for GetName which is of type Type
    var paramExp = Expression.Parameter(typeof(Type));
    
    // Calls static method GetName passing in the param
    var mCallGetName = Expression.Call(typeof(MyClass), "GetName", null, paramExp);
    Func<Type, string> resultWithArg = Expression.Lambda<Func<Type, string>>(mCallGetName, paramExp).Compile();
    
    // You can then call them like so... Print() just prints the string
    resultNoArg().Print();
    resultWithArg(typeof(string)).Print();
    resultWithArg(typeof(int)).Print();
    

    Alternatively, Instead of:

    var mCallGetTime = Expression.Call(typeof(MyClass), "GetTime", null);
    

    We could compose the Expression.Call using:

    // Get the method info for GetTime (note the Type[0] signifying no args taken by GetTime);
    var methodInfo = typeof(MyClass).GetMethod("GetTime", new Type[0]);
    var mCallGetTime = Expression.Call(methodInfo);
    

    Likewise for GetName:

    // Get the method info for GetName (note the new[] {typeof(Type)} signifying the arg taken by GetName
    var getNameMethodInfo = typeof(MyClass).GetMethod("GetName", new[] { typeof(Type)});
    var mCallGetName = Expression.Call(getNameMethodInfo, paramExp);