Domanda

Ho un albero delle espressioni che ho creato analizzando un Xml usando la classe di espressioni in C #. Vedi questa domanda .

Ho solo Aggiungi, Sottrai, Dividi, Moltiplica, Parametri e e o nel mio albero delle espressioni. C'è un modo per convertire questo ExpressionTree in un metodo richiamabile? ... o devo emettere IL manualmente?

Cordiali saluti,

È stato utile?

Soluzione

Ecco un esempio di entrambi gli approcci. Se ho perso qualcosa o vuoi maggiori informazioni, fammelo sapere.

static void Main()
{
    // try to do "x + (3 * x)"

    var single = BuildSingle<decimal>();
    var composite = BuildComposite<decimal>();

    Console.WriteLine("{0} vs {1}", single(13.2M), composite(13.2M));
}
// utility method to get the 3 as the correct type, since there is not always a "int x T"
static Expression ConvertConstant<TSource, TDestination>(TSource value)
{
    return Expression.Convert(Expression.Constant(value, typeof(TSource)), typeof(TDestination));
}
// option 1: a single expression tree; this is the most efficient
static Func<T,T> BuildSingle<T>()
{        
    var param = Expression.Parameter(typeof(T), "x");
    Expression body = Expression.Add(param, Expression.Multiply(
        ConvertConstant<int, T>(3), param));
    var lambda = Expression.Lambda<Func<T, T>>(body, param);
    return lambda.Compile();
}
// option 2: nested expression trees:
static Func<T, T> BuildComposite<T>()
{

    // step 1: do the multiply:
    var paramInner = Expression.Parameter(typeof(T), "inner");
    Expression bodyInner = Expression.Multiply(
        ConvertConstant<int, T>(3), paramInner);
    var lambdaInner = Expression.Lambda(bodyInner, paramInner);

    // step 2: do the add, invoking the existing tree
    var paramOuter = Expression.Parameter(typeof(T), "outer");
    Expression bodyOuter = Expression.Add(paramOuter, Expression.Invoke(lambdaInner, paramOuter));
    var lambdaOuter = Expression.Lambda<Func<T, T>>(bodyOuter, paramOuter);

    return lambdaOuter.Compile();
}

Personalmente, vorrei mirare al primo metodo; è sia più semplice che più efficiente. Ciò potrebbe comportare il passaggio del parametro originale attraverso una pila di codice nidificato, ma così sia. Ho un po 'di codice da qualche parte che prende " Invoke " approccio (composito) e riscrive l'albero come primo approccio (singolo), ma è piuttosto complesso e lungo. Ma molto utile per Entity Framework (che non supporta Expression.Invoke).

Altri suggerimenti

Devi creare una lambda, ad esempio

var lambda = Expression.Lambda<Func<float,int>>(body, param);
Func<float,int> method = lambda.Compile();
int v = method(1.0); // test

dove " body " è il tuo albero delle espressioni (prendendo un float, restituendo un int) che coinvolge il parametro ParameterExpression

Potresti anche trovare questo e questo utile.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top