I'm trying to create an ExpressionTree from one constant string array and one parameter.
var keys = "car,train".Split(','); // "car, train" will be given as a constant.
//var myModel = "MyModel-car"; // this will be given as a parameter
myModel => keys.Any(k => myModel.Contains(k)); // how to create this ExpressionTree?
I've read through this, but my case is different because the delegate (k => myModel.Contains(k)
) has actually two parameters. Here, the k
is determined by keys
which is a ConstantExpression at runtime. But in the Expression body, it is still a ParameterExpression instance.
I've tried like:
var modelParam = Expression.Parameter(typeof(string)); // Example value: "MyModel-car".
var keys = "car,train".Split(',').AsQueryable().Expression;
var anyMethod = typeof(Enumerable).GetMethods()
.First(x => x.Name == "Any" && x.GetParameters().Length == 1)
.MakeGenericMethod(typeof(string));
var containsMethod = typeof(String).GetMethods()
.Where(x => x.Name == "Contains" && x.GetParameters().Length == 1)
.First(x => x.GetParameters().First().ParameterType == typeof(string));
var key = Expression.Parameter(typeof(string));
var containsCallExpr = Expression.Call(modelParam, containsMethod, key);
var lambda = Expression.Lambda(containsCallExpr, key);
Expression anyCallExpr = Expression.Call(keys, anyMethod, lambda); // throw an exception
Expression expr = Expression.Lambda(anyCallExpr, modelParam);
However, the anycallExpr
line throws an exception:
Static method requires null instance, non-static method requires non-null instance
Does anyone know how to make this work?
[UPDATE]
Based on @Svyatoslav Danyliv's suggestion, I changed the order of argument but a different exception is shown:
Incorrect number of arguments supplied for call to method 'Boolean Any[String](System.Collections.Generic.IEnumerable
1[System.String])' (Parameter 'method')`
- I think this exception makes sense because I have two parameters actually.
CodePudding user response:
Try the following realization:
var modelParam = Expression.Parameter(typeof(string), "model") ; // Example value: "MyModel-car".
var keys = "car,train".Split(',').AsEnumerable();
var keysExpression = Expression.Constant(keys);
var containsMethod = typeof(string).GetMethods()
.Where(x => x.Name == nameof(string.Contains) && x.GetParameters().Length == 1)
.First(x => x.GetParameters().First().ParameterType == typeof(string));
var key = Expression.Parameter(typeof(string), "k");
var containsCallExpr = Expression.Call(modelParam, containsMethod, key);
var lambda = Expression.Lambda(containsCallExpr, key);
Expression anyCallExpr = Expression.Call(typeof(Enumerable), nameof(Enumerable.Any),
new[] { typeof(string) }, keysExpression, lambda);
Expression expr = Expression.Lambda(anyCallExpr, modelParam);