How to create a compiled lambda with method calls?

I am generating compiled getter methods at runtime for a given member. Right now, my code just assumes the result of the getter method is a string (great for testing). However, I would like to make this work with the custom converter class that I wrote, see the “ConverterBase” link that I added below.

I cannot figure out how to add a call to the converter class to my expression tree.

public Func<U, string> GetGetter<U>(MemberInfo info) { Type t = null; if (info is PropertyInfo) { t = ((PropertyInfo)info).PropertyType; } else if (info is FieldInfo) { t = ((FieldInfo)info).FieldType; } else { throw new Exception("Unknown member type"); } //TODO, replace with ability to specify in custom attribute ConverterBase typeConverter = new ConverterBase(); ParameterExpression target = Expression.Parameter(typeof(U), "target"); MemberExpression memberAccess = Expression.MakeMemberAccess(target, info); //TODO here, make the expression call "typeConverter.FieldToString(fieldValue)" LambdaExpression getter = Expression.Lambda(memberAccess, target); return (Func<U, string>)getter.Compile(); } 

I am looking for what to put in the second area of ​​TODO (I can handle the first :)).

The resulting compiled lambda should take an instance of type U as a parameter, call the specified member access function, then call the "FieldToString" converter method with the result and return the resulting string.

+1
c # lambda expression-trees
source share
2 answers

Can you illustrate that (if it was regular C #) you want the expression to be evaluated? I can write the expression easily enough - I just don't quite understand the question ...

(edit re comment) - in this case it will be something like:

  ConverterBase typeConverter = new ConverterBase(); var target = Expression.Parameter(typeof(U), "target"); var getter = Expression.MakeMemberAccess(target, info); var converter = Expression.Constant(typeConverter, typeof(ConverterBase)); return Expression.Lambda<Func<U, string>>( Expression.Call(converter, typeof(ConverterBase).GetMethod("FieldToString"), getter), target).Compile(); 

Or, if the type refuses to bind, you need to enter cast / convert:

  MethodInfo method = typeof(ConverterBase).GetMethod("FieldToString"); return Expression.Lambda<Func<U, string>>( Expression.Call(converter, method, Expression.Convert(getter, method.GetParameters().Single().ParameterType)), target).Compile(); 
+5
source share

You need to wrap the object in ExpressionConstant, for example. using Expression.Constant. Here is an example:

 class MyConverter { public string MyToString(int x) { return x.ToString(); } } static void Main() { MyConverter c = new MyConverter(); ParameterExpression p = Expression.Parameter(typeof(int), "p"); LambdaExpression intToStr = Expression.Lambda( Expression.Call( Expression.Constant(c), c.GetType().GetMethod("MyToString"), p), p); Func<int,string> f = (Func<int,string>) intToStr.Compile(); Console.WriteLine(f(42)); Console.ReadLine(); } 
+4
source share

All Articles