2010-09-08 13 views
10

niech będzie:Konwersja ekspresyjne drzewa

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

teraz muszę przejść EXP1 do _db.Messages.where(exp1); problemu mam tylko EXP2, muszę konwertować typ do wiadomości, wszystkie właściwości są takie same!

teraz zrobić to:

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

Problem z tym jest wejście paramter zostanie zmieniony tak! ale x w ciele lambda "x.mesID" jest starego typu.

jakikolwiek sposób na zmianę wszystkich typów parametrów w ciele lub zmianę parametru wejściowego w odwzorowaniu również odbija ciało?

Domyślam się, że jest to duży problem, który zawsze mam z LINQ, ponieważ pomiędzy warstwami nie mogę przekazać wygenerowanych klas, ponieważ spowoduje to połączenie warstw, więc muszę zrobić lekki klasy wag, teraz jak używać metody jak _db.Messages.where(); z warstwy busiess? !! podczas gdy warstwa busniess nic nie wie o typie wiadomości, tylko zna MessageDTO.

+0

(dodany przykład) –

Odpowiedz

10

Nie, zasadniczo. Drzewa wyrażeń są niezmienne i zawierają pełne dane meta członków (to jest, że mesID jest messageDTO.mesID). Aby to zrobić, musisz przebudować drzewo wyrażeń od początku (przez gościa), obsługując każdy typ węzła, który musisz obsługiwać.

Jeśli drzewo wyrażeń jest podstawowe, to powinno być OK, ale jeśli potrzebujesz obsługi całej gamy? ogromny PITA (szczególnie w .NET 4, który dodaje o wiele więcej typów węzłów).


podstawowy przykład, że robi tylko co jest wymagane dla przykładu; musisz dodać więcej typów węzłów dla bardziej złożonych wyrażeń:

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

co masz na myśli przez vistora? czy możesz dać mi przykład plz? – Stacker

+0

Implementacja odwiedzającego; tj. konstrukcja kodu, której używa się do przechodzenia przez całą strukturę drzewa, zwykle konstruując alternatywne drzewo (z węzłów liści z powrotem do katalogu głównego, ponieważ każda gałąź jest niezmienna). Może to sprowadzić się do ogromnego przełącznika (na typie węzła) z rekursywną obsługą dla każdego typu węzła. Spróbuję pobudzić przykład ... –

+0

dzięki Marc to zadziałało, muszę tylko sprawić, żeby to działało więcej ExpressionType – Stacker