次のプログラムの出力は次のとおりです。
最初: System.String。2 番目: System.String。
予想される結果は次のとおりです。最初: hello1。2 番目: hello2。
Expression.Assign(resultArrayAccessor, parameters[0]) でインデックスを 1 または 2 にハードコーディングすると機能しますが、変数 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;
}