Expression Lambda with types known at runtime

时间:2015-06-15 14:48:05

标签: c# lambda expression-trees

I am trying to make some Expressions where I will be using a lambda to create two methods: a selector and condition. Simplified the usage is condition(selector(data)), but the intemediate type is only known at runtime. I have the following code which works as long as the intemediate type is object, but at runtime I know the real type and would like to use that.

    public static ICondition<TData> GetRelayConditionByReflection(string name, string message, string assemblyName,
        string fullyQualifiedName, string conditionMethodName, string selectorMethodName) {
        var asm = Assembly.LoadFrom(assemblyName);
        var type = asm.GetType(fullyQualifiedName);
        var selectorMi = type.GetMethod(selectorMethodName, BindingFlags.Static | BindingFlags.Public);
        var conditionMi = type.GetMethod(conditionMethodName, BindingFlags.Static | BindingFlags.Public);

        var tCondType = selectorMi.ReturnType;
        var returnType = typeof(RelayCondition<,>);
        var typeArgs = new[] { typeof(TData), tCondType };



        var paramTData = Expression.Parameter(typeof(TData), "data");
        var selector = Expression.Lambda<Func<TData, object>>(
            Expression.Call(selectorMi, paramTData), paramTData).Compile();

        var paramTCondition = Expression.Parameter(tCondType, "condition");

        var condition = Expression.Lambda<Func<object, bool>>(
            Expression.Call(conditionMi, paramTCondition), paramTCondition).Compile();



        return (ICondition<TData>)Activator.CreateInstance(returnType.MakeGenericType(typeArgs), name, condition, message, selector);
    }

Specifically, there is Expression.Lambda<Func<TData, object>> and Expression.Lambda<Func<object, bool>> where object currently only allows the intemediate type to be object.

Is it possible to create this with a type known only at runtime? I am open for other approaches for the entire problem, as long as performance isn't attrocius.

1 个答案:

答案 0 :(得分:2)

If you don't need implicit downcasting (for example declaring a Func<object> when in truth you method returns a Func<Foo>), you can use the non-generic Expression.Lambda() method. It returns a LambdaExpression, but in truth it returns a Expression<> of Func<> or of Action downcasted to LambdaExpression (Expression<> is a subclass of LambdaExpression), so:

var condition = Expression.Lambda(
        Expression.Call(conditionMi, paramTCondition), paramTCondition).Compile();

now condition is a Delegate, but in truth it is a Func<> (or an Action if it had a return type void).