Expression Against Predicate Problems
I have a little problem where I need to create an expression tree to represent a request by a user. Since I don't have time to create all the possible cases of user input, I figured that expression trees would help me with this question.
For the most part, he has. I am, however, a little puzzled. In the code below, I am trying to execute List.Find with a dynamically generated expression. In short, this expression:
list.Find(m => m.ListOfStrings.Exists(s => s == "cookie"));
where m is
class MyClass
{
public List<string> ListOfStrings { get; set; }
}
I got to the point of creation
s => s == "cookie"
with expressions, no problem. I also declared the info method for Exists
var existsMethod = typeof(MyClass)
.GetProperty("ListOfStrings")
.PropertyType
.GetMethod("Exists");
The only problem I am running into is creating an expression to call the specified method using a lambda as a parameter like this
var findLambda = Expression.Lambda(
Expression.Call(
Expression.Property(
Expression.Parameter(typeof(MyClass), "m"),
typeof(MyClass).GetProperty("ListOfStrings")),
existsMethod,
existsLambda),
Expression.Parameter(
typeof (MyClass),
"m"));
This 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 can I overcome this?
Complete 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());
}
a source to share
Delegates are of different types:
public delegate bool Predicate<T>(T obj);
public delegate TResult Func<T, TResult>(T arg);
Method Exists
(s Find
) are waiting Predicate<T>
. The Lambda expression is compiled at run time before Func<T, TResult>
.
Try the following:
var existsLambda = Expression.Lambda(typeof(Predicate<string>),
Expression.Equal(
Expression.Parameter(typeof(string), "s"),
Expression.Constant("cookie")),
Expression.Parameter(typeof(string), "s"));
You can also use a generic Lambda Function :
var existsLambda = Expression.Lambda<Predicate<string>>(Expression.Equal(
Expression.Parameter(typeof(string), "s"),
Expression.Constant("cookie")),
Expression.Parameter(typeof(string), "s"));
a source to share
If you look at the message, it tells you that Predicate is incompatible with Func.
The Predicate is now defined as such:
public delegate bool Predicate<T>(
T obj
)
and you have Func as such:
public delegate TResult Func<T, Result>(
T arg1
)
Compatible, you are trying to make these 2 delegates compatible:
public delegate bool MyClassPredicate ( MyClass obj )
public delegate bool StringFunc ( string arg1 )
Those. string! = MyClass.
Hope this made sense.
a source to share