I am trying to create a runtime lambda function of an arbitrary type, that collects the arguments, that were supplied to it, in a list of objects and passes them to another method of type void Method(List<object> list)
to process them. I wrote this code, but got really confused with the result:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
namespace LambdaTest
{
class LambdaCreator
{
ParameterExpression[] Parameters;
int Index = 0;
public ParameterExpression Next()
{
return Parameters[Index++];
}
public void ResetIndex()
{
Index = 0;
}
public void Bar(List<object> parameters)
{
foreach (var p in parameters)
{
PrintType(p);
}
}
public void PrintType(object arg)
{
Console.WriteLine(arg.GetType().Name);
}
public T CreateLambda<T>() where T : class
{
var barMethod = GetType().GetMethod("Bar");
Parameters = typeof(T).GetMethod("Invoke")
.GetParameters()
.Select(x => Expression.Parameter(x.ParameterType))
.ToArray();
var parametersCount = Expression.Constant(Parameters.Length);
var listType = typeof(List<object>);
var list = Expression.Variable(listType);
var index = Expression.Variable(typeof(int));
var thisObject = Expression.Constant(this);
var resetIndex = GetType().GetMethod("ResetIndex");
var next = GetType().GetMethod("Next");
var printType = GetType().GetMethod("PrintType");
var add = listType.GetMethod("Add");
var breakLabel = Expression.Label();
var block = Expression.Block(
new ParameterExpression[] { list, index },
Expression.Call(thisObject, printType, Parameters.FirstOrDefault()),
Expression.Call(thisObject, resetIndex),
Expression.Assign(list, Expression.New(listType)),
Expression.Loop(
Expression.Block(
Expression.IfThen(Expression.GreaterThanOrEqual(index, parametersCount), Expression.Break(breakLabel)),
Expression.Call(list, add, Expression.Call(thisObject, next)),
Expression.AddAssign(index, Expression.Constant(1))
),
breakLabel
),
Expression.Call(thisObject, barMethod, list)
);
var lambda = Expression.Lambda(typeof(T), block, Parameters);
var compiledLambda = lambda.Compile() as T;
return compiledLambda;
}
}
class Program
{
delegate void Foo(string a, int b);
static void Main(string[] args)
{
var test = new LambdaCreator();
var l = test.CreateLambda<Foo>();
l("one", 2);
}
}
}
The output of the program was:
String
PrimitiveParameterExpression`1
PrimitiveParameterExpression`1
I was expecting to get:
String
String
Int32
Somehow I lose the values of the arguments when I put them in a list and pass it to the Bar
method. Can someone tell me where is the problem I how can I fix it. Or is there another way to collect the arguments and pass them through? I'm really new to this expression trees stuff. Thanks in advance!
Aucun commentaire:
Enregistrer un commentaire