2010-09-08 145 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