2009-03-17 32 views
14

He usado expresiones C# antes en base a lamdas, pero no tengo experiencia en componerlas a mano. Dado un Expression<Func<SomeType, bool>> originalPredicate, quiero crear un Expression<Func<OtherType, bool>> translatedPredicate.C# Cómo convertir una expresión <Func <SomeType>> en una expresión <Func <OtherType>>

En este caso SomeType y OtherType tienen los mismos campos, pero no están relacionados (sin herencia y no basados ​​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 Model, para mantener mi modelo en POCO. Quiero pasar expresiones al repositorio (como una forma de especificaciones) pero deben basarse en las entidades modelo. Pero no puedo pasar esas expresiones al contexto de datos, ya que espera expresiones basadas en las entidades LINQ to SQL.

+1

La respuesta es en este tema: http://stackoverflow.com/questions/4601844/expression-tree-copy-or-convert – jeanlou1370

Respuesta

20

Con Expression, la forma más sencilla es con una conversión expresió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 }); 
    } 
} 

Nota sin embargo que este será apoyado de manera diferente por diferentes proveedores. A EF podría no gustarle, por ejemplo, incluso si LINQ-to-SQL sí.

La otra opción es reconstruir el árbol de expresiones completamente, utilizando la reflexión para buscar los miembros correspondientes. Mucho mas complejo

+0

hombre eres un genio ... gracias !!! :) – SteveCl

+0

Espero que a L2EF le guste esto porque estoy convirtiendo una expresión de una interfaz a la clase concreta, y para devolver los resultados como un IQueryable ... ¿cree que hay una manera de reducir los gastos generales? – IAbstract

+0

+1: esto me pone en marcha de la manera correcta, creo. Aun así, definitivamente aprendí algo nuevo. Estoy recibiendo una relación faltante de EF.Voy a trabajar en ello un poco más antes de plantear una nueva pregunta. Me pregunto si necesito adjuntar las tablas a través del método EntityCollection ... – IAbstract

2

No hay una forma implícita de hacer la traducción. Usted tiene que envolver su delegado existente dentro de un lambda que crea un nuevo tipo del tipo de argumento:

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

Dónde OtherTypeFromSomeType crea la instancia OtherType del argumento SomeType.

+0

1; ¡golpéame! –

+2

La pregunta era sobre expresiones, no sobre delegados. No puede usar este enfoque para invocar una sub-expresión; es mas complejo –

+0

Vaya, no leí con cuidado. De todos modos, la técnica es básicamente la misma, las expresiones solo requieren más trabajo (aunque técnicamente mi código aún funcionaría después de compilar 'originalPredicate', y usar' Expresión <…> 'en lugar de' var' ;-)). –

3

Hay otra forma que he encontrado, que también incluye envolver 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(); 
} 
0

que tenían el mismo problema que usted y lo fijé como este con EF:

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

Marco de la entidad sabe cómo construir el comando correcto sql. Convertir la expresión es mucho más complicado, porque está diseñado para ser inmutable y podría causar efectos de tiempo de ejecución no deseados si haces algo mal y, en mi caso al menos, no es necesario.

Cuestiones relacionadas