Domanda

Ho già usato espressioni C # basate su lamdas, ma non ho esperienza nel comporle a mano. Data un'espressione < Func < SomeType, bool > > originalPredicate , voglio creare un espressione < Func < OtherType, bool > > translatedPredicate .

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

Background: ho un'implementazione del repository basata su LINQ to SQL. Progetto le entità LINQ to SQL sulle mie entità Model, per mantenere il mio modello in POCO. Voglio passare espressioni al repository (come una forma di specifiche) ma dovrebbero essere basate sulle entità del modello. Ma non riesco a passare quelle espressioni al contesto dei dati, poiché prevede espressioni basate sulle entità LINQ to SQL.

È stato utile?

Soluzione

Con Espressione , il modo più semplice è con una conversione espressione :

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 è quella di ricostruire l'albero delle espressioni completamente , usando la riflessione per trovare i membri corrispondenti. Molto più complesso.

Altri suggerimenti

C'è un altro modo che ho trovato, che include anche il wrapping del 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();
}

Non esiste un modo implicito per eseguire la traduzione. Devi racchiudere il tuo delegato esistente all'interno di un lambda che crea un nuovo tipo dal tipo di argomento:

var translatedPredicate = x => originalPredicate(OtherTypeFromSomeType(x))

Dove OtherTypeFromSomeType crea l'istanza OtherType dall'argomento SomeType .

Ho avuto lo stesso problema con te e l'ho risolto in questo modo con EF:

var viewModeValue = dbContext.Model.Select(m => new ViewModel{Field = m.Field}).Where(predicate) //predicate is an Expression<Func<ViewModel, bool>>

Entity Framework sa come creare il comando sql corretto. La conversione dell'espressione è molto più complicata, perché è costruita per essere immutabile e potrebbe causare effetti di runtime indesiderati se si fa qualcosa di sbagliato e, nel mio caso almeno, non è necessario.

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