Per vari motivi sto costruendo un lambda C # in modo dinamico usando le strutture degli alberi delle espressioni. ad esempio, posso creare Func <string, bool> in runtime come mostrato nel seguente frammento.
public static bool myMethod( object obj ) { … }
// Construct a Func<string,bool>
var myMethod = GetType().GetMethod("myMethod");
var lambdaParams = new ParameterExpression[] {Expression.Parameter(typeof (string))};
var callMyMethod = Expression.Call(myMethod, lambdaParams);
var lambda = Expression.Lambda(typeof(Func<string,bool>), callMyMethod, lambdaParams);
var del = (Func<string,bool>)lambda.Compile();
del("foo"); // works
Comunque se uso lo stesso codice per provare a fare un Func <int, bool> o un Func <DateTime, bool> esplode dove indicato con la seguente strana eccezione:
// Construct a Func<DateTime,bool> or perhaps a struct type fails... why?
var myMethod = GetType().GetMethod("myMethod");
var lambdaParams = new ParameterExpression[] {Expression.Parameter(typeof (DateTime))};
var callMyMethod = Expression.Call(myMethod, lambdaParams); // Blows up here…
System.ArgumentException: Expression of type 'System.DateTime' cannot be used for parameter of type 'System.Object' of method 'Boolean myMethod(System.Object)'
Quindi, string funziona e List <string> funziona ma int32 non funziona né DataTime. Cosa sta succedendo? Non so come funzionino gli interni profondi di C #, ma suppongo che sia dovuto a un vero manipolo come primitivo e forse DateTime (che è anche una struttura) ...
Qualsiasi aiuto con questo sarebbe molto apprezzato.
grazie, Pat
A quanto ho capito, Expression.Call
non esegue il auto-boxing degli argomenti di tipo value. Non riesco a trovare alcuna documentazione in tal senso, ma è menzionata su questa pagina del forum .
Una soluzione alternativa sarebbe esplicitamente fare la conversione di boxe nell'espressione con Expression.TypeAs
.
Crea un'espressione unaria che rappresenta un riferimento esplicito o una conversione di boxing in cui viene fornito un valore null se la conversione ha esito negativo.
Nel tuo caso, questo dovrebbe funzionare:
var boxedParams = lambdaParams.Select(p => Expression.TypeAs(p, typeof(object)))
.ToArray();
var callMyMethod = Expression.Call(myMethod, boxedParams);
(Non hai bisogno dei fantasiosi lambda se c'è un solo parametro)
A seconda dell'utilizzo effettivo, potrebbe essere necessario verificare se la conversione di boxing è necessaria a seconda che il / i tipo / i in questione sia (sono) di tipo / i di valore.
Controlla questo: devi inserire il DateTime, dato che DateTime non è un tipo di riferimento!
// Construct a Func<DateTime,bool>
var myMethod = typeof(Program).GetMethod("myMethod");
var param = Expression.Parameter(typeof(DateTime));
var boxy = Expression.TypeAs(param, typeof(object));
var callMyMethod = Expression.Call(myMethod, boxy);
var lambda = Expression.Lambda(typeof(Func<DateTime, bool>), callMyMethod, new ParameterExpression[] { param });
var del = (Func<DateTime,bool>)lambda.Compile();
del(DateTime.Now); // works