I've got a bit of a challenge where I have to create an expression tree to represent a query input by the user. Since I don't have the time to create all the possible cases of user input, I figured that expression trees would aid me in solving this.
For the most part, it has. I am, however, a bit stumped. I am in the code below trying to perform a List.Find with a dynamically created expression. The expression, in short, is this:
list.Find(m => m.ListOfStrings.Exists(s => s == "cookie"));
where m is
class MyClass
{
public List<string> ListOfStrings { get; set; }
}
I've gotten so far as to create
s => s == "cookie"
with expressions, no problem. I've also declared a methodinfo for Exists
var existsMethod = typeof(MyClass)
.GetProperty("ListOfStrings")
.PropertyType
.GetMethod("Exists");
The only problem I have is creating an expression to invoke said method with the lambda as a parameter like so
var findLambda = Expression.Lambda(
Expression.Call(
Expression.Property(
Expression.Parameter(typeof(MyClass), "m"),
typeof(MyClass).GetProperty("ListOfStrings")),
existsMethod,
existsLambda),
Expression.Parameter(
typeof (MyClass),
"m"));
It gives an understandable exception that
Expression of type 'System.Func`2[System.String,System.Boolean]' cannot be used for parameter of type 'System.Predicate`1[System.String]' of method 'Boolean Exists(System.Predicate`1[System.String])'
How the heck can I overcome this?
Full code:
private class MyClass
{
public List<string> ListOfStrings { get; set; }
}
public void SomeMethod()
{
var myObject = new MyClass();
myObject.ListOfStrings = new List<string>();
myObject.ListOfStrings.Add("cookie");
myObject.ListOfStrings.Add("biscuit");
List<MyClass> list = new List<MyClass>();
list.Add(myObject);
var existsLambda = Expression.Lambda(
Expression.Equal(
Expression.Parameter(typeof(string), "s"),
Expression.Constant("cookie")),
Expression.Parameter(typeof(string), "s"));
var existsMethod = typeof(MyClass).GetProperty("ListOfStrings").PropertyType.GetMethod("Exists");
var findLambda = Expression.Lambda(
Expression.Call(
Expression.Property(
Expression.Parameter(typeof(MyClass), "m"),
typeof(MyClass).GetProperty("ListOfStrings")),
existsMethod,
existsLambda),
Expression.Parameter(
typeof (MyClass),
"m"));
list.Find((Predicate<MyClass>)findLambda.Compile());
}