Come lanciare un albero di espressione lambda in c #?

c# casting expression-trees lambda

Domanda

Ho un'espressione di espressione dell'albero

var lambdaExpr 

che quando compilato genererà

Action<Type,int>

Comunque vorrei avvolgere questo e generare un'espressione che, una volta compilata, genererà

Action<object, int>

e dovrò forzare un cast sul primo argomento all'azione per convertirlo prima di passarlo al lambda originale

object --- cast ---> Type

che quando viene eseguito sarà ovviamente attraverso un'eccezione di runtime se il cast non è possibile.

Come faccio a racchiudere l'espressione dell'albero delle espressioni originali in quella nuova?

Nello specifico ho bisogno di aggiungere del codice extra dove indicato di seguito per ottenere i tipi corretti.

private static Action<object, TProp> GenerateSetter<TProp>(Type type, string propertyName )
{
     var property = type.GetProperty
         (propertyName, BindingFlags.Public 
         | BindingFlags.Instance
         | BindingFlags.NonPublic);
     MethodInfo setterMethodInfo = property.SetMethod;
     ParameterExpression paramo = Expression.Parameter(type, "param");
     ParameterExpression parami = Expression.Parameter(typeof(TProp), "newvalue");
     MethodCallExpression methodCallSetterOfProperty = 
         Expression.Call(paramo, setterMethodInfo, parami);
     Expression setPropertyValueExp = 
         Expression.Lambda(methodCallSetterOfProperty, paramo, parami);

     // This line below fails because setPropertyValueExp is an
     //  Action with first argument
     // being the type passed in at runtime. I need to wrap it with a lambda that 
     // casts the object to the correct type.

     var setPropertyValueLambda = 
         ( Expression<Action<object, TProp>> ) setPropertyValueExp;
     var setterFunc = setPropertyValueLambda.Compile();
     return setterFunc;
}

Risposta accettata

Devi prendere l' Action<Type,int> lambda e generare Action<object,int> lambda che esegue il cast e la chiama:

 var p=Expression.Parameter(typeof(object));
 var conversion=Expression.Convert(p,type);
 var call=Expression.Invoke(setPropertyValueExp,conversion);
 var lambda=Expression.Lambda(call,p);
 return lambda.Compile() as Action<object,int>;

Risposta popolare

Dovresti aggiungere il cast alla tua espressione (usando Expression.Convert ):

private static Action<object, TProp> GenerateSetter<TProp>(Type type, string propertyName )
{
     var property = type.GetProperty
         (propertyName, BindingFlags.Public 
         | BindingFlags.Instance
         | BindingFlags.NonPublic);
     MethodInfo setterMethodInfo = property.SetMethod;
     ParameterExpression paramo = Expression.Parameter(typeof(object), "param");
     ParameterExpression parami = Expression.Parameter(typeof(TProp), "newvalue");
     MethodCallExpression methodCallSetterOfProperty = 
         Expression.Call(Expression.Convert(paramo, type), setterMethodInfo, parami);
     var setPropertyValueExp = 
         Expression.Lambda<Action<object, TProp>>(methodCallSetterOfProperty, paramo, parami);

     var setterFunc = setPropertyValueExp.Compile();
     return setterFunc;
}


Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché
Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché