Call method Expression Tree in C# - c#

I want create expression with reflection in c#.
I am target script is:
using (var service = new MyProxy<IProductsService>())
{
var response = service.DoAction<Response<List<Product>>>(srv => srv.GetProducts());
}
How to (srv => srv.GetProducts() script is generate with expression tree?
Edit:
I am sorry for the wrong expression.
wherein IProductsService, Response<List<Product>> and GetProducts are actually unknown types. I take generic on runtime.
I wrote the following methods(CreateExpression) to try. But Expression property = Expression.Call(methodReturnType, methodName.Name, new Type[]{ } ,parameter); line gives the following error:
No method 'GetProducts' exists on type
'ServiceFoundation.Response1[System.Collections.Generic.List1[ServiceFoundation.Products.Product]]'.
Next in line for I have not tested it yet.
Method:
private void CreateExpression(Type interfaceType, Type methodReturnType, MethodInfo methodName)
{
ParameterExpression parameter = Expression.Parameter(interfaceType, "srv");
Expression property = Expression.Call(methodReturnType, methodName.Name, new Type[]{ } ,parameter);
Type expressionType = typeof(Expression<>);
Type lambdaType = typeof(LambdaExpression);
Type funcType = typeof(Func<,>);
Type delegateType = funcType.MakeGenericType(interfaceType, methodReturnType);
Type expression = expressionType.MakeGenericType(delegateType);
MethodInfo mI = typeof(Expression).GetMethod("Lambda");
MethodInfo lambda = mI.MakeGenericMethod(delegateType);
var ex = lambda.Invoke(this, new object[] { delegateType, property, parameter });
}
Hopefully I can express.

If you have an
Expression<Action<Response>>
you can call
.Compile()
on it and it returns an
Action<Response>
which you can then invoke normally.
eg
Expression<Action<Response>> exp = resp => Console.WriteLine(resp);
Action<Response> func = exp.Compile();
func(myResponse);
However, if that's all you need to do, you might find it simpler not to use expressions at all;
Action<Response> func = resp => Console.WriteLine(resp);
func(myResponse);

I succeeded after a long struggle. I examined different questions here.
and in the end I solved this way:
private Expression CreateExpression(Type interfaceType, Type methodReturnType, MethodInfo methodName)
{
ParameterExpression parameter = Expression.Parameter(interfaceType, "srv");
Expression callExpression = Expression.Call(parameter, methodName.Name,null, null);
Type expressionType = typeof(Expression<>);
Type lambdaType = typeof(LambdaExpression);
Type funcType = typeof(Func<,>).MakeGenericType(interfaceType, methodReturnType);
Type expressionGenericType = expressionType.MakeGenericType(funcType);
string methodSignature = "System.Linq.Expressions.LambdaExpression Lambda(System.Linq.Expressions.Expression, System.Linq.Expressions.ParameterExpression[])";
var lambdaMethod = typeof(Expression).GetMethods()
.Single(mi => mi.ToString() == methodSignature);
Expression lambdaExpression = (Expression)lambdaMethod.Invoke(this, new object[] { callExpression, new ParameterExpression[] { parameter } });
return lambdaExpression;
}

Related

How to get expression for a local variable

I am making a framework that supports plugins, therefore it load classes defined in plugin dlls when the application starts.
foreach (Type t in assembly.GetTypes()) {
if (t.IsAssignableTo(typeof(AIGameBodyBehaviour))) {
AIGameBodyBehaviourFactory factory = new AIGameBodyBehaviourFactory() {
Id = t.Name,
NewAIGameBodyBehaviour = Expression.Lambda<Func<AIGameBodyBehaviourFactoryArguments, AIGameBodyBehaviour>>(
Expression.New(
t.GetConstructor(new Type[] {typeof(AIGameBodyBehaviourFactoryArguments) }),
new Expression[] {
//stuck at here
}
),
new ParameterExpression[] {
Expression.Parameter(typeof(AIGameBodyBehaviourFactoryArguments), "arguments")
}
).Compile()
};
EntityLoaderInterface.AddAIGameBodyBehaviourFactory(factory);
}
}
As shown above, the complied lambda takes a parameter of type AIGameBodyBehaviourFactoryArguments and return an instance of AIGameBodyBehaviour. The body of the lambda function is a call to the constructor of the subclass of AIGameBodyBehaviour defined by user.
The parameter of the lambda expression is named "arguments". This name should be reused as the expression repressenting the value to be passed into the constructor. However, I cannot findout how to do this even after examining the documentation provided by Microsoft and some research via Google.
When you are stuck with expressions, you can consider SharpLab. If I understood you correctly, you want to have an expression that looks like this:
Expression<Func<AIGameBodyBehaviourFactoryArguments, AIGameBodyBehaviour>> expression =
(arguments) => new AIGameBodyBehaviour(arguments);
SharpLab will show you that the compiler will turn this line into
ParameterExpression parameterExpression = Expression.Parameter(typeof(AIGameBodyBehaviourFactoryArguments), "arguments");
ConstructorInfo constructor = (ConstructorInfo)MethodBase.GetMethodFromHandle((RuntimeMethodHandle)/*OpCode not supported: LdMemberToken*/);
Expression[] array = new Expression[1];
array[0] = parameterExpression;
NewExpression body = Expression.New(constructor, (IEnumerable<Expression>)array);
ParameterExpression[] array2 = new ParameterExpression[1];
array2[0] = parameterExpression;
Expression<Func<AIGameBodyBehaviourFactoryArguments, AIGameBodyBehaviour>> expression = Expression.Lambda<Func<AIGameBodyBehaviourFactoryArguments, AIGameBodyBehaviour>>(body, array2);
(See Sharplab)
You can see that the same instance for ParameterExpression is used as the second parameter in Expression.New and in the second parameter in Expression.Lambda. Hence your code should look like this:
foreach (Type t in assembly.GetTypes()) {
if (t.IsAssignableTo(typeof(AIGameBodyBehaviour))) {
var parameterExpression = Expression.Parameter(typeof(AIGameBodyBehaviourFactoryArguments), "arguments");
AIGameBodyBehaviourFactory factory = new AIGameBodyBehaviourFactory() {
Id = t.Name,
NewAIGameBodyBehaviour = Expression.Lambda<Func<AIGameBodyBehaviourFactoryArguments, AIGameBodyBehaviour>>(
Expression.New(
t.GetConstructor(new Type[] {typeof(AIGameBodyBehaviourFactoryArguments) }),
new Expression[] {
parameterExpression
}
),
new ParameterExpression[] {
parameterExpression
}
).Compile()
};
EntityLoaderInterface.AddAIGameBodyBehaviourFactory(factory);
}
}

Is there a way to compile a lambda expression passing an object generated run time?

I need to compile a lambda expression passing an object generated run time. Here is code I have so far.
An example:
var anonType = new { Name = "Florida" }.GetType();
var myObj = Activator.CreateInstance(anonType, "Florida");
var expression = Expression.Parameter(myObj.GetType(), "Name");
var property = Expression.Property(expression, "Name");
var rule = new Rule("Name", "NotEqual", "Florida");
ExpressionType tBinary;
if (!Enum.TryParse(rule.Operator, out tBinary)) return;
var propertyType = myObj.GetType().GetProperty(rule.MemberName).PropertyType;
var right = Expression.Constant(Convert.ChangeType(rule.TargetValue, propertyType));
var result = Expression.MakeBinary(tBinary, property, right);
var expr = Expression.Lambda<Func<Type, bool>>(result, expression).Compile();
var isValid = expr(anonType);
I'm getting an error at the line when its trying to compile Lambda expression.
Additional information: ParameterExpression of type '<>f__AnonymousType0`1[System.String]' cannot be used for delegate parameter of type 'System.Type'
Not sure what you want to achieve with that, but will answer your direct question. You can compile lambda like this in your case:
// create Func<AnonymousType, bool>
var func = typeof(Func<,>).MakeGenericType(anonType,typeof(bool));
// compile
var expr = Expression.Lambda(func, result, expression).Compile();
// invoke
var isValid = expr.DynamicInvoke(new { Name = "NotFlorida" });

How to Call a Generic Method using "Expression.Parameter" and "Expression.Call" APIs

Using the Expression Tree API I want to generate code for code that looks like this:
FieldInfo enumFieldInfo = enumFieldInfoSet.SingleOrDefault(fieldInfo => fieldInfo.Name == enumName);
I have written this code but it's not working:
var enumerableType = typeof(Enumerable);
var enumerableGenericType = typeof(IEnumerable<>).MakeGenericType(typeof(FieldInfo));
var predicateGenericType = typeof(Func<>).MakeGenericType(typeof(Func<FieldInfo, bool>));
ParameterExpression fieldInfoSource = Expression.Parameter(enumerableGenericType, "fieldInfoSource");
ParameterExpression predicateSource = Expression.Parameter(predicateGenericType, "funcPredicateOnFieldInfo");
var arrayOfTypes = new Type[] { enumerableGenericType, predicateGenericType };
MethodCallExpression SingleOrDefaultMethodCall = Expression.Call(enumerableType, "SingleOrDefault",arrayOfTypes, fieldInfoSource, predicateSource);
Here is the runtime error: No generic method 'SingleOrDefault' on type 'System.Linq.Enumerable' is compatible with the supplied type arguments and arguments. No type arguments should be provided if the method is non-generic.
I have tried a number of combinations of type coercion but still have not stumbled on the right combination. I know that the SingleOrDefault is an Extension method on the Enumerable class and that it needs two parameters; I've look at the code via the debugger and have written to code inspect its properties at run-time; what am I missing.
The problem is that you are using the Expression.Call overload which takes a type, and for a static method you need an overload with MethodInfo.
void Main()
{
Expression<Func<IEnumerable<FieldInfo>, Func<FieldInfo,bool>, FieldInfo>> singleOrDefaultExpr = (l,p) => l.SingleOrDefault(p);
var callSource = (MethodCallExpression)singleOrDefaultExpr.Body;
var method = callSource.Method;
var collectionParameter = Expression.Parameter(typeof(IEnumerable<FieldInfo>), "enumFieldInfoSet");
var enumNamePredicateParameter = Expression.Parameter(typeof(Func<FieldInfo,bool>), "enumNamePredicate");
var body = Expression.Call(method, collectionParameter, enumNamePredicateParameter);
var lambda = Expression.Lambda<Func<IEnumerable<FieldInfo>, Func<FieldInfo, bool>, FieldInfo>>(body, collectionParameter, enumNamePredicateParameter);
var f = lambda.Compile();
Console.WriteLine(f(typeof(Apple).GetFields(), fi => fi.Name == "color").Name);
}
class Apple
{
public string color;
}
Also, you can use another method to find the required MethodInfo:
var method = typeof(Enumerable)
.GetMethods()
.Single(m => m.Name == "SingleOrDefault" && m.GetParameters().Count() == 2)
.MakeGenericMethod(new[] {typeof(FieldInfo)});
UPDATE:
There is actually a simpler method, and you were on the right track, but your code had en error.
var collectionParameter = Expression.Parameter(typeof(IEnumerable<FieldInfo>), "enumFieldInfoSet");
var enumNamePredicateParameter = Expression.Parameter(typeof(Func<FieldInfo,bool>), "enumNamePredicate");
var body = Expression.Call(typeof(Enumerable), "SingleOrDefault", new[] { typeof(FieldInfo)}, collectionParameter, enumNamePredicateParameter);
var lambda = Expression.Lambda<Func<IEnumerable<FieldInfo>, Func<FieldInfo, bool>, FieldInfo>>(body, collectionParameter, enumNamePredicateParameter);
The problem was that SingleOrDefault has only one generic type parameter: 'FieldInfo' in this case:
SingleOrDefault<FieldInfo>(....
Don't mix it up with the method parameters, there are two of them:
SingleOrDefault<GenericParameter>(
this IEnumerable<GenericParameter> firstMethodParameter,
Func<GenericParameter, bool> secondMethodParameter
)
George did a great job in getting me on the right track and did provide me a partial answer; I re-fashion my code so that is was clear to me. This is an example of code that I wanted to machine generate in testing our Meta-programming runtime. I am providing more code than is necessary for the specific problem but I wanted the others to see the greater context.
// Code to Generate Enum Field Metadata ...
string enumName = Enum.GetName(theEnumType, theOrdinalEnumValue);
Array enumValues = Enum.GetValues(theEnumType);
object enumValue = enumValues.GetValue(theOrdinalEnumValue);
object enumObject = Enum.ToObject(theEnumType, theOrdinalEnumValue);
// Create Local variables of the types targeted for assignment expressions that we will make in the generated code
var enumVariables = Expression.RuntimeVariables(Expression.Variable(typeof(string), "gcEnumName"),
Expression.Variable(typeof(Array), "gcEnumValues"),
Expression.Variable(typeof(object), "gcEnumValue"),
Expression.Variable(theEnumType, "gcEnumObject"),
Expression.Variable(typeof(FieldInfo), "gcFieldInfoOnEnum"));
// Setup the Input Parameters for calls into Enum and Array Types in preperation for Assignments
ParameterExpression theInputOfEnumType = Expression.Variable(typeof(Type), "theInputOfEnumType");
ParameterExpression theEnumFieldNameValue = Expression.Variable(typeof(string), "theEnumFieldNameValue");
ParameterExpression aEnumObjectIndexValue = Expression.Variable(typeof(int), "aEnumObjectIndexValue");
ParameterExpression anArrayOfEnumObjects = Expression.Variable(typeof(Array), "anArrayOfEnumObjects");
ParameterExpression anEnumerableObject = Expression.Variable(typeof(Enumerable), "anEnumerableObject");
ParameterExpression directEnumTypeResolved = Expression.Variable(theEnumType, "directEnumTypeResolved");
ParameterExpression fieldInfoOnEnum = Expression.Variable(typeof(FieldInfo), "fieldInfoOnEnum");
var fieldInfoEnumerableRepresentation = typeof(Enumerable);
In perpetration of making calls to "Expression.Call" we need to get some MethodInfo data
// We need to generate MethodInfo on the Methods we want to call in the generated code. This is metadata
// we need to call the Expression.Call API.
MethodInfo enumGetNameMethodInfo = enumMetadata.GetMethods().FirstOrDefault(info => info.Name == "GetName");
MethodInfo enumGetValuesMethodInfo = enumMetadata.GetMethods().FirstOrDefault(info => info.Name == "GetValues");
MethodInfo enumGetValueMethodInfo = arraryMetadata.GetMethods()
.FirstOrDefault(methodInfo => (methodInfo.Name == "GetValue") && methodInfo.GetParameters().Any(param =>param.ParameterType == typeof(int)));
MethodInfo enumToObjectMethodInfo = enumMetadata.GetMethods()
.FirstOrDefault(info => info.Name == "ToObject");
// We know that there exist a number of polymorphic instances of the "SingleOrDefault" Extension method
// so we use the name of the parameter named "predicate" to locate our method. **FYI Can't use the MethodInfo data in a call to Expression.Call - It's a generic definition**.
MethodInfo enumerableSingleOrDefaultInfo = fieldInfoEnumerableRepresentation.GetMethods()
.FirstOrDefault(methodInfo => (methodInfo.Name == "SingleOrDefault") &&
methodInfo.GetParameters()
.Any(param => param.Name == "predicate"));
Here is the final code that works in making a call to a Generic Method:
// An approach to setup a Generic method call that will be used in an Expression.Assign call
// I decompose this code so for debugging purposes
// I create the "inputOfTSourceType" as a Generic Type because in the Definition of "SingleOrDefault" method there is only one Generic Parameter;
// also, take special note that in the assemblage of Expression.Call methods any of the methods that take a MethodInfo instance you can't pass in
// a "Generic" method definition. If you take a look at the code that is called it will throw and exception if it detects the IsGenericMethodDefinition
// flag is true.
var inputOfTSourceType = typeof(IEnumerable<>).MakeGenericType(typeof(FieldInfo)); // This is the type on the "source" TSource parameter
var predicateOfFuncType = typeof(Func<FieldInfo, bool>); // This is the type on the "predicate" parameter
// Take note there that we only define one(1) type here ("inputParameterType"); this is the type we wish apply to the Generic Type TSource
// declaration: public static TSource SingleOrDefault<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate);
var inputParameterType = new[] {typeof(FieldInfo)}; // This is the type we must match to "source" parameter
// The "SingleOrDefault" method can take two parameters and in this case I need to pass in a lambda expression as the predicate.
// Se we need two parameters.
ParameterExpression fieldInfoSource = Expression.Parameter(inputOfTSourceType, "fieldInfoSource"); // This is: this IEnumerable<TSource>
ParameterExpression predicateSource = Expression.Parameter(predicateOfFuncType, "funcPredicateOnFieldInfo"); // This is: Func<TSource, bool> predicate
MethodCallExpression SingleOrDefaultMethodCall =
Expression.Call(fieldInfoEnumerableRepresentation, // This is the Object Instance for which the
"SingleOrDefault", // The Name of the Generic Method
inputParameterType, // The Generic Type
fieldInfoSource, // this is the "this" source parameter
predicateSource); // this the "predicate" parameter
Expression localEnumNameAssignment =
Expression.Assign(enumVariables.Variables[0], EnumGetNameMethodCall);
Expression localEnumObjectsAssignment =
Expression.Assign(enumVariables.Variables[1], EnumGetValauesMethodCall);
Expression localEnumObjectAssignment =
Expression.Assign(enumVariables.Variables[2], ArrayGetValueMethodCall);
Expression localEnumTypeAssignment =
Expression.Assign(enumVariables.Variables[3], Expression.Convert(EnumToObjectMethodCall, theEnumType));
Expression localFieldInfoAssignment =
Expression.Assign(enumVariables.Variables[4], Expression.Convert(SingleOrDefaultMethodCall, typeof(FieldInfo)));
BlockExpression blockExpression =
Expression.Block(enumVariables,
localEnumNameAssignment,
localEnumObjectsAssignment,
localEnumObjectAssignment,
localEnumTypeAssignment,
localFieldInfoAssignment,
enumTypeToReturn);
Here's the generated code:
$gcEnumName = .Call System.Enum.GetName(
$theInputOfEnumType, $gcEnumName = (System.String)$theEnumFieldNameValue)
$gcEnumValues = .Call System.Enum.GetValues($theInputOfEnumType)
$gcEnumValue = .Call $anArrayOfEnumObjects.GetValue((System.Int32) $theOrdinalEnumValue)
$gcEnumObject = (WorkflowMessagingCommands).Call System.Enum.ToObject(
$theInputOfEnumType,
(System.Object)$theEnumInstance)
// Here is the generated code to call "SignleOrDefault"
$gcFieldInfoOnEnum = .Call System.Linq.Enumerable.SingleOrDefault(
$thisSourceType,
$predciateType)

Turn a property name as a string into a Linq Expression

I need to turn an string that represents a property name on an interface into an expression. I have most of it working, there is just 1 piece that I can't figure out at the end.
static Expression<Func<T, int>> MakeGetter<T>(string propertyName)
{
var input = Expression.Parameter(typeof(T));
var property = typeof(T).GetProperty(propertyName) ??
GetProperty(propertyName, typeof(T));
var expr = Expression.Property(input, property);
var propType = property.PropertyType.Name;
switch (propType.ToLower())
{
case "string":
return Expression.Lambda<Func<T, string>>(expr, input);
case "int":
return Expression.Lambda<Func<T, int>>(expr, input);
}
}
private static PropertyInfo GetProperty(string propertyName, Type i)
{
var baseInterfaces = i.GetInterfaces();
foreach (var baseInterface in baseInterfaces)
{
var property = baseInterface.GetProperty(propertyName);
return property ?? GetProperty(propertyName, baseInterface);
}
return null;
}
The one problem that I have is at the end of the MakeGetter function I don't know if the function is a string or int or some other type and have no way of knowing until after I do all of the reflection, so how can I create this method, so that it is generic and will return an Expression correctly.
Have a look here at an example of generating lambda expressions at runtime. These lines from the article show how to generate lambda expression:
var parameterExpression = Expression.Parameter(typeof(TEntity), "x");
var memberExpression = Expression.PropertyOrField(parameterExpression, prop.Name);
var memberExpressionConversion = Expression.Convert(memberExpression, typeof(object));
var lambda = Expression.Lambda<Func<TEntity, object>>(memberExpressionConversion, parameterExpression);
Now that you've declared your intent for this in the comments, I believe that the accepted answer here is what you're looking for. Even if it's not doing exactly what you're looking for, these lines can carry over:
// TODO: Get 'type' from the property you want.
Type delegateType = typeof(Func<,>).MakeGenericType(typeof(T), type);
LambdaExpression lambda = Expression.Lambda(delegateType, expr, arg);
You could return LambdaExpression, or just use the extension methods found in that answer, or use DynamicLinq. I guess the moral of the story (as it often is) is that its probably been done already :).

Exception when building Expression to call StringBuilder.Append(Object) with DateTime

I've built a ToStringBuilder (found here) which reflects on types and dynamically builds Expressions to compile fast ToString methods.
It works well but I've just discovered it errors on DateTimes. It chokes when trying to build an call to StringBuilder.Append(Object) passing a DateTime. Do I need to create an expression to box value types? How is this best done?
I've created the following test case to demonstrate the failure.
// passes
[Test]
public void AppendDateTime()
{
StringBuilder sb = new StringBuilder();
sb.Append(new DateTime());
}
// throws
[Test]
public void ExpressionAppendDateTime()
{
ParameterExpression sbArgExpression = Expression.Parameter(typeof(StringBuilder), "sb");
ParameterExpression dateTimeArgExpression = Expression.Parameter(typeof(DateTime), "dateTime");
var appendMethod = typeof(StringBuilder).GetMethod("Append", new[] {typeof(DateTime)});
var call = Expression.Call(sbArgExpression, appendMethod, dateTimeArgExpression);
// throws on this line
var lambda = Expression.Lambda<Action<StringBuilder, DateTime>>(call, sbArgExpression, dateTimeArgExpression).Compile();
var datetime = new DateTime();
var sb = new StringBuilder();
lambda.Invoke(sb, datetime);
}
The exception is..
System.ArgumentException was unhandled by user code
Message=Expression of type 'System.DateTime' cannot be used for parameter of type 'System.Object' of method 'System.Text.StringBuilder Append(System.Object)'
Source=System.Core
StackTrace:
at System.Linq.Expressions.Expression.ValidateOneArgument(MethodBase method, ExpressionType nodeKind, Expression arg, ParameterInfo pi)
at System.Linq.Expressions.Expression.ValidateArgumentTypes(MethodBase method, ExpressionType nodeKind, ReadOnlyCollection`1& arguments)
at System.Linq.Expressions.Expression.Call(Expression instance, MethodInfo method, IEnumerable`1 arguments)
at System.Linq.Expressions.Expression.Call(Expression instance, MethodInfo method, Expression[] arguments)
at Tests.TestToStringBuilder.ExpressionAppendDateTime() in
InnerException:
Solved it, had to use Expression.TypeAs to type non-primitive value types as Object
[Test]
public void ExpressionAppendDateTime()
{
ParameterExpression sbArgExpression = Expression.Parameter(typeof(StringBuilder), "sb");
ParameterExpression dateTimeArgExpression = Expression.Parameter(typeof(DateTime), "dateTime");
var appendMethod = typeof(StringBuilder).GetMethod("Append", new[] {typeof(DateTime)});
Type t = typeof(DateTime);
Expression arg;
if (t.IsValueType && !t.IsPrimitive)
{
arg = Expression.TypeAs(dateTimeArgExpression, typeof(object));
}
else
{
arg = dateTimeArgExpression;
}
var call = Expression.Call(sbArgExpression, appendMethod, arg);
var lambda = Expression.Lambda<Action<StringBuilder, DateTime>>(call, sbArgExpression, dateTimeArgExpression).Compile();
var datetime = new DateTime();
var sb = new StringBuilder();
lambda.Invoke(sb, datetime);
}

Categories

Resources