Reputation: 119
Output of the following program is:
First: System.String. Second: System.String.
The expected result is: First: hello1. Second: hello2.
If i hardcode the index to 1 or 2 in Expression.Assign(resultArrayAccessor, parameters[0]) it works, but i need to have the index following 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;
}
Upvotes: 3
Views: 1630
Reputation: 119
Finally figured it out, much easier syntax aswell as actually working ;)
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();
}
Upvotes: 3