2010-09-08 95 views
10

让有:转换表达式树

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

现在我需要传递给EXP1问题_db.Messages.where(exp1);是我只有EXP2,我需要的类型转换为信息,所有属性都是一样的!

现在我这样做:

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

问题,这是输入放慢参数得到改变,是的!但lambda“x.mesID”体内的x是旧类型的。

任何方式改变身体的所有参数类型或改变输入参数在它离开它反映身体呢?

我想这是我一直对LINQ的一个大问题,因为在图层之间我无法传递生成的类,因为这会使图层耦合,所以我必须制作轻量级类,现在我该如何使用方法像_db.Messages.where();从业务层?!!而busniess层不知道关于消息类型的任何信息,它只知道MessageDTO。

+0

(添加示例) – 2010-09-08 12:49:37

回答

10

不,基本上。表达式树是不可变的,并且包含完整的成员元数据(即mesIDmessageDTO.mesID)。为此,您必须重新构建表达式树(通过访问者),处理您需要支持的每种节点类型。

如果表达式树是基本这应该没问题,但是如果您需要支持整个色域?一个巨大的PITA(特别是在.NET 4中,它增加了更多的节点类型)。


一个基本例如,做只是什么是必需的例子;您需要为更复杂的表达式添加更多节点类型:

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

您是什么意思由via vistor?你能给我一个例子吗? – Stacker 2010-09-08 12:31:11

+0

访客实施;即您用于遍历整个树结构的一些代码构造,通常构造替代树(从叶节点返回到根,因为每个分支都是不可变的)。这可能归结为一个巨大的交换机(在节点类型上),对每个节点类型都进行递归处理。我会尝试掀起一个例子... – 2010-09-08 12:36:31

+0

感谢马克它的工作,我只需要使它支持更多ExpressionType – Stacker 2010-09-08 12:59:13