简体   繁体   中英

How to use lambda expression parameter in “sub” expression?

I'd like to be able to build expressions like the following delegate:

Func<object[], object> createSomeType1 = (args) =>
{
    return new SomeType1((P1)args[0], (P2)args[1], (P3)args[2]);
};

I'm just starting out with hand made expressions so excuse me if this is a rather simple question (or I'm misunderstanding something).

I know that to create the constructor with the right types, I'd do the following:

var p1 = Expression.Parameter(typeof(P1));
var p2 = Expression.Parameter(typeof(P2));
var p3 = Expression.Parameter(typeof(P3));
var someType1Exp = Expression.New(constructorInfo, p1, p2, p3);

And then I know the "outer" lambda is, I think, declared like this:

Expression<Func<object[], object>>.Lambda<Func<object[], object>>(
            someType1Exp,
            Expression.Parameter(typeof(object[])));

I'm having trouble wrapping my head around how to "pass" the parameter from the outer expression to the inner expression and then cast it to the right type.

Any hints in the right direction are appreciated.

I'm on iPod, so can't give a full example at the moment: but:

  • declare a param of type object[] ( Expression.Param(typeof(object[])) ) and store that in a variable
  • for each term from the array, use the array indexer to obtain an expression to the indexer, and " Convert " or "cast" (iPod again!) to cast it
  • use Expression.Invoke , passing the inner expression plus the indexer+cast you generated above

I'll be happy to do a complete example later if you need (when I'm at a PC)


Full example:

Type[] types = new Type[] { typeof(int), typeof(float), typeof(string) };

var constructorInfo = typeof(SomeType).GetConstructor(types);
var parameters = types.Select((t,i) => Expression.Parameter(t, "p" + i)).ToArray();
var someType1Exp = Expression.New(constructorInfo, parameters);
var inner = Expression.Lambda(someType1Exp, parameters);

var args = Expression.Parameter(typeof(object[]), "args");          
var body = Expression.Invoke(inner,
    parameters.Select((p,i) => Expression.Convert(Expression.ArrayIndex(args, Expression.Constant(i)), p.Type)).ToArray());
var outer = Expression.Lambda<Func<object[], object>>(body, args);
var func = outer.Compile();

object[] values = {1, 123.45F, "abc"};
object obj = func(values);
Console.WriteLine(obj);

Or as a single expression:

Type[] types = new Type[] { typeof(int), typeof(float), typeof(string) };   
var constructorInfo = typeof(SomeType).GetConstructor(types);

var args = Expression.Parameter(typeof(object[]), "args");          
var body = Expression.New(constructorInfo,
    types.Select((t,i) => Expression.Convert(Expression.ArrayIndex(args, Expression.Constant(i)), t)).ToArray());
var outer = Expression.Lambda<Func<object[], object>>(body, args);
var func = outer.Compile();

object[] values = {1, 123.45F, "abc"};
object obj = func(values);
Console.WriteLine(obj);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM