Create array of all ExpressionTree/Func-parameters

c# expression expression-trees lambda

Question

The following program's output is:

System.String is first. Second: System.String.

The anticipated outcome is: First, hello1. Next, hello2.

If I set the Expression's index hardcoded to 1 or 2. It works using Assign(resultArrayAccessor, parameters[0]), but I need the index to come after the variable i.

    public static void Main()
    {
        var type = typeof(Func<string, string, object>);
        var del = GenerateFunc<Func<string, string, object>>(type);
        del("hello1", "hello2");
        Console.ReadLine();
    }

    public static T GenerateFunc<T>(Type type)
    {
        var i = Expression.Parameter(typeof (int), "i");

        var x = type.GetMethod("Invoke");
        var target = typeof (Program).GetMethod("Target");

        var resultArray = Expression.Parameter(typeof(object[]), "result");
        var parameterArray = Expression.Parameter(typeof(ParameterExpression[]), "parameters");

        var resultArrayAccessor = Expression.ArrayAccess(resultArray, i);
        var parameterArrayAccessor = Expression.ArrayAccess(parameterArray, i);

        var label = Expression.Label();

        var parameters = x.GetParameters().Select(p => Expression.Parameter(p.ParameterType, p.ParameterType.ToString())).ToArray();

        var block = Expression.Block(x.ReturnType,
            new[] { resultArray, i, parameterArray },
            Expression.Assign(resultArray, Expression.Constant(new object[parameters.Length])),
            Expression.Assign(parameterArray, Expression.Constant(parameters)),
            Expression.Loop(
                Expression.Block(
                    Expression.IfThenElse(
                        Expression.LessThan(i, Expression.Constant(parameters.Length)),
                            Expression.Block(
                                Expression.Assign(resultArrayAccessor, parameterArrayAccessor),
                                Expression.PostIncrementAssign(i)
                            ),
                        Expression.Break(label)
                    )
                ),
                label
            ),

            Expression.Call(target, resultArray)
        );


        return Expression.Lambda<T>(block, parameters).Compile();
    }

    public static object Target(object[] test)
    {
        Console.WriteLine("First: " + test[0] + ". Second: " + test[1] + ".");
        return null;
    }
1
3
10/26/2012 11:41:25 AM

Accepted Answer

I finally got it to work, and the syntax was lot simpler.

public static T GenerateFunc<T>(Type type)
{
    var target = typeof (Program).GetMethod("Target");

    var invokeMethod = type.GetMethod("Invoke");
    var parameters = invokeMethod
      .GetParameters()
      .Select(pi => Expression.Parameter(pi.ParameterType, pi.Name))
      .ToList();

    var parametersExpression = Expression.NewArrayInit(typeof(object), parameters);
    var body = Expression.Call(target, parametersExpression);
    return Expression.Lambda<T>(body, parameters).Compile();
}
3
10/13/2013 5:19:25 AM


Related Questions





Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow