C # Cómo convertir una expresión > a una expresión >

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

Pregunta

He usado expresiones C # antes basadas en lamdas, pero no tengo experiencia en componerlas a mano. Dada una Expression<Func<SomeType, bool>> originalPredicate , quiero crear una Expression<Func<OtherType, bool>> translatedPredicate .

En este caso, SomeType y OtherType tienen los mismos campos, pero no están relacionados (no hay herencia y no se basan en una interfaz común).

Antecedentes: Tengo una implementación de repositorio basada en LINQ to SQL. Proyecto las entidades LINQ to SQL a mis entidades de modelo, para mantener mi modelo en POCO. Quiero pasar expresiones al repositorio (como una forma de especificaciones) pero deberían estar basadas en las entidades modelo. Pero no puedo pasar esas expresiones al contexto de datos, ya que espera expresiones basadas en el LINQ a las entidades SQL.

Respuesta aceptada

Con Expression , la forma más sencilla es con una expresión de conversión:

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 });
    }
}

Tenga en cuenta, sin embargo, que esto será soportado de manera diferente por diferentes proveedores. Es posible que a EF no le guste, por ejemplo, incluso si LINQ-to-SQL lo hace.

La otra opción es reconstruir el árbol de expresiones completamente , usando la reflexión para encontrar los miembros correspondientes. Mucho más complejo.


Respuesta popular

Hay otra forma que he encontrado, que también incluye envolver a su delegado original.

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


Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow