2010-09-08 20 views
10

: Que no hayaConvertir árboles de expresión

Expression<Func<Message, bool>> exp1 = x => x.mesID == 1; 
Expression<Func<MessageDTO, bool>> exp2 = x => x.mesID == 1; 

ahora tengo que pasar a exp1 _db.Messages.where(exp1); problema es que sólo tengo exp2, i necesidad de convertir el tipo de mensaje, Todas las propiedades son las mismas!

ahora hago esto:

var par = Expression.Parameter(typeof(Message)); 
    var ex = (Expression<Func<Message, bool>>)Expression.Lambda(exp2.Body, par); 

problema con esto es el parametro de entrada se cambia sí! pero la x dentro del cuerpo de la lambda "x.mesID" es del tipo antiguo.

cualquier forma de cambiar todos los parámetros escriba también en el cuerpo o cambie el parámetro de entrada para que refleje el cuerpo también?

supongo que este es un gran problema que siempre tengo con LINQ, ya que entre las capas no puedo pasar las clases generadas, ya que esto hará capas acopladas, así que tengo que hacer clases ligeras, ¿cómo utilizo un método? como _db.Messages.where(); de la capa de busiess? !! mientras que la capa de busniess no sabe nada acerca del tipo de mensaje, solo conoce MessageDTO.

+0

(ejemplo añadido) –

Respuesta

10

No, básicamente. Los árboles de expresión son inmutables y contienen metadatos de miembro completo (es decir, mesID es messageDTO.mesID). Para hacer esto, debería reconstruir el árbol de expresiones desde cero (a través de un visitante), manejando cada tipo de nodo que necesita soportar.

Si el árbol de expresiones es básico, esto debería estar bien, pero si necesita admitir toda la gama? un gran PITA (especialmente en .NET 4, que agrega muchos más tipos de nodos).


Un básica ejemplo que hace simplemente lo que se requiere para el ejemplo; que tendría que añadir más nodos tipos de expresiones más complejas:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Linq.Expressions; 
static class Program 
{ 
    static void Main() 
    { 
     Expression<Func<Message, bool>> exp1 = x => x.mesID == 1; 
     var exp2 = Convert<Message, MessageDTO>(exp1); 
    } 
    static Expression<Func<TTo, bool>> Convert<TFrom, TTo>(Expression<Func<TFrom, bool>> expr) 
    { 
     Dictionary<Expression,Expression> substitutues = new Dictionary<Expression,Expression>(); 
     var oldParam = expr.Parameters[0]; 
     var newParam = Expression.Parameter(typeof(TTo), oldParam.Name); 
     substitutues.Add(oldParam, newParam); 
     Expression body = ConvertNode(expr.Body, substitutues); 
     return Expression.Lambda<Func<TTo,bool>>(body, newParam); 
    } 
    static Expression ConvertNode(Expression node, IDictionary<Expression, Expression> subst) 
    { 
     if (node == null) return null; 
     if (subst.ContainsKey(node)) return subst[node]; 

     switch (node.NodeType) 
     { 
      case ExpressionType.Constant: 
       return node; 
      case ExpressionType.MemberAccess: 
       { 
        var me = (MemberExpression)node; 
        var newNode = ConvertNode(me.Expression, subst); 
        return Expression.MakeMemberAccess(newNode, newNode.Type.GetMember(me.Member.Name).Single()); 
       } 
      case ExpressionType.Equal: /* will probably work for a range of common binary-expressions */ 
       { 
        var be = (BinaryExpression)node; 
        return Expression.MakeBinary(be.NodeType, ConvertNode(be.Left, subst), ConvertNode(be.Right, subst), be.IsLiftedToNull, be.Method); 
       } 
      default: 
       throw new NotSupportedException(node.NodeType.ToString()); 
     } 
    } 
} 
class Message { public int mesID { get; set; } } 
class MessageDTO { public int mesID { get; set; } } 
+0

¿Qué quiere decir por medio de vistor? ¿Puedes darme un ejemplo por favor? – Stacker

+0

Una implementación de visitante; es decir, algún constructo de código que utilice para recorrer toda la estructura de árbol, normalmente construyendo un árbol alternativo (desde los nodos de hoja hasta la raíz, ya que cada rama es inmutable). Esto podría reducirse a un cambio enorme (en tipo de nodo), con manejo recursivo para cada tipo de nodo. Trataré de dar un ejemplo ... –

+0

gracias Marc funcionó solo tengo que hacer que admita más ExpressionType – Stacker

Cuestiones relacionadas