How to initialize the Expression.Call object in System.Linq.Expression C# - c#

I want to initialize the Expression Call outside the if else condition. As i have to use it to generate expression body because i have two different type coming from database i.e int and int?. My Code is below.
I am getting error to instantiate the toString object.
var parameterExp = Expression.Parameter(typeof(T), "type");
var propertyExp = Expression.Property(parameterExp, propertyName);
MethodInfo method = typeof(string).GetMethod(methodType, new[] { typeof(string) });
var searchValue = Expression.Constant(propertyValue.ToLower(), typeof(string));
var toString = new MethodCallExpression();
if (propertyName == nameof(CustomerListDto.Id))
{
toString = Expression.Call(propertyExp, typeof(int).GetMethod("ToString", System.Type.EmptyTypes));
}
else
{
toString = Expression.Call(propertyExp, typeof(int?).GetMethod("ToString", System.Type.EmptyTypes));
}
var body = Expression.Call(toString, method, searchValue);
return Expression.Lambda<Func<T, bool>>(body, parameterExp);
I don't know exactly how to initialize ExpressionCall. This is the thing which i want to know. Currently it is giving me error "MethodCallExpression does not contains constructor that takes 0 argument". I searched a lot but could not find any solution.

You can't instantiate a MethodCallExpression manually as the constructor is private. You can get an instance of MethodCallExpression as the return value of Expression.Call though. You probably just want to declare it as
MethodCallExpression toString;
// Then assign it with Expression.Call(...);
if (propertyName == nameof(CustomerListDto.Id))
{
toString = Expression.Call(propertyExp, typeof(int).GetMethod("ToString", System.Type.EmptyTypes));
}
else
{
toString = Expression.Call(propertyExp, typeof(int?).GetMethod("ToString", System.Type.EmptyTypes));
}

Related

Cannot figure out syntax for Expression.Call for Guid.Equals going into a predicate

Trying to write a way to sort of dynamically look at data passed to me via json (I don't have it strictly typed). I have been mulling this over for days and I am 100% unsure of the syntax, but I get the concept.
Can anyone assist me write this so it works? The first 'if' needs to create a Linq "contains" with StringComparer.OrdinalIgnoreCase and the second if needs to create a Guid.Equals call.
I feel like a true idiot, but it has been close to 2 days and endless google searches. I even read the interface for the .Call commands and theres ~14 of them and I can't figure out which is for what. I haven't been able to get this to work even once.
public static IQueryable<T> FilterDynamic<T>(this IQueryable<T> query, string fieldName, object values)
{
ParameterExpression param = Expression.Parameter(typeof(T), "e");
MemberExpression prop = Expression.PropertyOrField(param, fieldName);
// We use nullable guids in <T>, so i have to convert to actual guid
UnaryExpression convertedExp = Expression.Convert(prop, prop.Type.GenericTypeArguments.Single());
MethodCallExpression body;
if (convertedExp.Type == typeof(string))
{
body = Expression.Call(typeof(Enumerable), "Contains", new[] {typeof(string)},
Expression.Constant(values), prop);
}
if (convertedExp.Type == typeof(Guid))
{
MethodInfo methd = convertedExp.Type.GetMethod("Equals", BindingFlags.Instance | BindingFlags.Public, null,new Type[] { typeof(object) }, null);
body = Expression.Call(prop.Type, "Equals", new[] {typeof(string)}, Expression.Constant(values), prop);
}
// Other types need to just not do anything.
Expression<Func<T, bool>> predicate = Expression.Lambda<Func<T, bool>>(body, param);
return query.Where(predicate);
}
The error I get on line 35 is No generic method 'Equals' on type 'System.Guid' is compatible with the supplied type arguments and arguments. No type arguments should be provided if the method is non-generic.
EDIT:
I had to change my second if block like this:
body = Expression.Call(convertedExp, methd, Expression.Constant(values));
All my answers were found by reading this code https://github.com/dotnet/corefx/blob/master/src/System.Linq.Expressions/src/System/Linq/Expressions/MethodCallExpression.cs

Call method Expression Tree in 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;
}

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 :).

Expression.Call - Calling linq extension: FirstOrDefault, Where

I am trying to create the following dynamically, however I am having problems calling the extension method FirstOrDefault:
using(var context = new Entities())
{
var list = context.Engines.Include("Cars").Select(e => e.Cars.FirstOrDefault()).ToList();
}
I have the following
Expression parameter = Expression.Parameter(typeof(Engine), "e");
Expression property = Expression.Property(parameter, "Cars");
parameter = {e}
property = {e.Cars}
Those are good, but I am encountering a problem when I try and call the FirstOrDefault method:
var result = Expression.Call(typeof(Queryable), "FirstOrDefault", new type[] { typeof(Car)}, property);
I would like to get
result = {e.Cars.FirstOrDefault()}
but I am getting an InvalidOperationException
No generic method 'FirstOrDefault' on
type 'System.Linq.Queryable' is
compatible with the supplied type
arguments and arguments. No type
arguments should be provided if the
method is non-generic.
Any help would be much appreciated.
Are you sure e.Cars is an IQueryable<T>?
If not, you can't pass it to Queryable.FirstOrDefault<T>(IQueryable<T>).
If it's an IEnumerable<T>, change your code to call Enumerable.FirstOrDefault<T>(IEnumerable<T>):
var result =
Expression.Call(
typeof(Enumerable),
"FirstOrDefault",
new Type[] { TypeSystem.GetElementType(property.Type) },
property);

Categories

Resources