2010-08-16 10 views
5

Básicamente estoy tratando de hacer this, pero no sé qué será T, entonces estoy construyendo cosas usando árboles de Reflexión y Expresión.Convertir func en predicado usando la reflexión en C#

// 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 }); 

Básicamente, tengo un List<Book>, lo que estoy tratando de reflexionar y Invoke su método Find. El método Find necesita un Predicate<Book> en lugar de Func<Book, bool>, y he estado golpeando mi cabeza contra esto durante unas horas.

Editar: Esta es la primera parte de la traza de error:

System.MissingMethodException: Constructor on type 'System.Predicate`1[[MyProject.Book, MyProject, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]' not found. 
+0

Si alguien necesita ver la parte en la que invocar el método Find, puedo también la oferta, pero pensé que iría en detrimento de lo esencial parte de la pregunta. –

Respuesta

3

Afortunadamente esto es bastante fácil de hacer, simplemente cambiando su llamada a Expression.Lambda:

Type predicateType = typeof(Predicate<>).MakeGenericType(itemType); 
LambdaExpression lambda = Expression.Lambda(predicateType, equality, predParam); 
Delegate compiled = lambda.Compile(); 

No está claro qué tenías que ver con el resultado, fíjate ... si la versión de tipo débil está bien para ti, debería estar bien.

+0

¿Quiso escribir Predicate <,> (con una coma)? –

+0

Lo dudo, ya que solo se necesita 1 tipo arg. :) –

+0

@Jon: No. No estoy seguro de qué versión del código viste: realizó al menos un par de ediciones, en parte debido a la incompetencia y en parte debido a una mala interpretación de la pregunta :) –

0

No estoy seguro si esto es lo mismo que la respuesta de Jon:

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); 
} 
+0

Lo siento, traté de comunicar que no tengo que suministrar T explícitamente. Entonces, en lugar de tener la línea 1 escrita explícitamente, Type itemType sería un parámetro para su solución. –

Cuestiones relacionadas