C # Come convertire un'espressione > a un'espressione >

c# expression-trees lambda linq-to-sql repository-pattern

Domanda

Ho usato le espressioni C # prima basate su lamdas, ma non ho esperienza nel compilarle a mano. Data Expression<Func<SomeType, bool>> originalPredicate , voglio creare Expression<Func<OtherType, bool>> translatedPredicate .

In questo caso, SomeType e OtherType hanno gli stessi campi, ma non sono correlati (nessuna ereditarietà e non basati su un'interfaccia comune).

Background: ho implementato un repository basato su LINQ to SQL. Progetto le entità LINQ su SQL per le entità del mio Modello, per mantenere il mio modello in POCO. Voglio passare le espressioni al repository (come una forma di specifiche) ma dovrebbero essere basate sulle entità del modello. Ma non posso passare quelle espressioni al contesto dati, dal momento che si aspetta espressioni basate sul LINQ su entità SQL.

Risposta accettata

Con Expression , il modo più semplice è con un'espressione di conversione:

class Foo {
    public int Value { get; set; }
}
class Bar {
    public int Value { get; set; }
}
static class Program {
    static void Main() {
        Expression<Func<Foo, bool>> predicate =
            x => x.Value % 2 == 0;
        Expression<Func<Bar, Foo>> convert =
            bar => new Foo { Value = bar.Value };

        var param = Expression.Parameter(typeof(Bar), "bar");
        var body = Expression.Invoke(predicate,
              Expression.Invoke(convert, param));
        var lambda = Expression.Lambda<Func<Bar, bool>>(body, param);

        // test with LINQ-to-Objects for simplicity
        var func = lambda.Compile();
        bool withOdd = func(new Bar { Value = 7 }),
             withEven = func(new Bar { Value = 12 });
    }
}

Si noti tuttavia che questo sarà supportato in modo diverso da diversi provider. Ad EF potrebbe non piacere, ad esempio, anche se LINQ-to-SQL lo fa.

L'altra opzione è di ricostruire completamente l' albero delle espressioni, utilizzando la reflection per trovare i membri corrispondenti. Molto più complesso.


Risposta popolare

C'è un altro modo che ho trovato, che include anche il wrapping del tuo delegato originale.

Func<T, object> ExpressionConversion<U>(Expression<Func<T, U>> expression)
{
    Expression<Func<T, object>> g = obj => expression.Compile().Invoke(obj);
    return g.Compile();
}


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é