Convert func to predicate using reflection in C#
I'm basically trying to do this, but I don't know what T will be, so I'm building things up using Reflection and Expression trees.
// Input (I don't know about "Book")
Type itemType = typeof(Book);
// Actual Code
// Build up func p => p.AuthorName == "Jon Skeet"
ParameterExpression predParam = Expression.Parameter(itemType, "p");
Expression left = Expression.Field(predParam, itemType.GetField("AuthorName"));
Expression right = Expression.Constant("Jon Skeet", typeof(string));
Expression equality = Expression.Equal(left, right);
Delegate myDelegate = Expression.Lambda(equality, new ParameterExpression[] { predParam }).Compile(); // Not sure if I need this
// Build up predicate type (Predicate<Book>)
Type genericPredicateType = typeof(Predicate<>);
Type constructedPredicateType = genericPredicateType.MakeGenericType(new Type[] { itemType });
// I need an instance to use this predicate, right? (** This Fails **)
object predicateInstance = Activator.CreateInstance(constructedPredicateType, new object[] { myDelegate });
Basically, I have a List<Book>
, which I'm trying to reflect on and Invoke
its Find
method. The Find
method needs a Predicate<Book>
instead of Func<Book, bool>
, and I've been beating my head against this for a few hours.
Edit: Here is the first part of the error trace:
System.MissingMethodException: Constructor on type 'System.Predicate`1[[MyProject.Book, MyProject, Version=1.0.0.0, Culture=neutral, PublicKe开发者_开发问答yToken=null]]' not found.
Fortunately this is pretty easy to do, just by changing your call to Expression.Lambda
:
Type predicateType = typeof(Predicate<>).MakeGenericType(itemType);
LambdaExpression lambda = Expression.Lambda(predicateType, equality, predParam);
Delegate compiled = lambda.Compile();
It's not clear what you needed to do with the result, mind you... if the weakly-typed version is okay for you, that should be fine.
Not sure if this is the same as Jon's answer:
public static Predicate<T> GetPredicate<T>()
{
Type itemType = typeof(T);
ParameterExpression predParam = Expression.Parameter(itemType, "p");
Expression left = Expression.Field(predParam, itemType.GetField("AuthorName"));
Expression right = Expression.Constant("Jon Skeet", typeof(string));
Expression equality = Expression.Equal(left, right);
Func<T, bool> function = (Func<T, bool>)Expression.Lambda(equality, new[] { predParam }).Compile();
return new Predicate<T>(function);
}
精彩评论