2010-08-16 11 views
5

In pratica sto provando a fare this, ma non so cosa sarà T, quindi sto costruendo le cose usando gli alberi di Reflection ed Expression.Converti func per predicate usando reflection in 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 }); 

Fondamentalmente, ho un List<Book>, che sto cercando di riflettere e Invoke suo metodo Find. Il metodo Find ha bisogno di un Predicate<Book> invece di Func<Book, bool> e ho battuto la testa contro questo per alcune ore.

Edit: Ecco la prima parte della Traccia di errore:

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

Se qualcuno ha bisogno di vedere la parte in cui invoco il metodo Find, posso fornire anche questo, ma ho pensato che sarebbe sminuire l'essenziale parte della domanda. –

risposta

3

Fortunatamente questo è abbastanza facile da fare, semplicemente cambiando la vostra chiamata a Expression.Lambda:

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

non è chiaro che cosa avevi bisogno di fare con il risultato, bada bene ... se la versione tipizzata debolmente va bene per te, dovrebbe andare bene.

+0

Volevi digitare Predicato <,> (con una virgola)? –

+0

Ne dubito, dal momento che richiede solo 1 tipo arg. :) –

+0

@Jon: No. Non sono sicuro di quale versione del codice hai visto - ha subito almeno un paio di modifiche, in parte a causa dell'incompetenza e in parte a causa di una lettura errata della domanda :) –

0

Non sono sicuro se questo è lo stesso come la risposta di 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

Scusa, ho cercato di comunicare che non ho T per fornire esplicitamente. Quindi, invece di scrivere in modo esplicito la riga 1, digitare itemType sarebbe un parametro della soluzione. –