2010-09-08 8 views
10

Qu'il y ait:Convertir des arbres d'expression

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

maintenant je dois passer à exp1 _db.Messages.where(exp1); problème que j'ai est exp2, je dois convertir le type de message, toutes les propriétés sont les mêmes!

maintenant je fais ça:

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

est la paramter entrée est changée oui! mais le x dans le corps du lambda "x.mesID" est du type ancien.

de toute façon de changer tous les paramètres de type dans le corps aussi ou de modifier le paramètre d'entrée en dehors de refléter le corps aussi?

je suppose que c'est un gros problème que j'ai toujours avec LINQ, car entre les couches je ne peux pas passer les classes générées, car cela va faire des couches couplées, donc je dois faire des classes légères, maintenant comment utiliser une méthode comme _db.Messages.where(); de la couche busiess? !! tandis que la couche busniess ne sait rien sur le type de message, elle ne connaît que MessageDTO.

+0

(exemple ajouté) –

Répondre

10

Non, fondamentalement. Les arbres d'expression sont immuables et contiennent des métadonnées de membre complet (c'est-à-dire que mesID est messageDTO.mesID). Pour ce faire, vous devrez reconstruire l'arbre d'expression à partir de zéro (via un visiteur), en gérant chaque type de nœud que vous devez prendre en charge.

Si l'arbre d'expression est de base cela devrait être OK, mais si vous avez besoin de prendre en charge l'ensemble de la gamme? un énorme PITA (surtout dans .NET 4, qui ajoute beaucoup plus de types de nœuds).


Un exemple de base qui fait juste ce qui est nécessaire pour l'exemple; vous auriez besoin d'ajouter plus de noeuds types d'expressions plus complexes:

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

ce que tu veux dire par l'intermédiaire vistor? pouvez-vous me donner un exemple plz? – Stacker

+0

Une implémentation de visiteur; c'est-à-dire une construction de code que vous utilisez pour traverser toute la structure arborescente, en construisant typiquement un arbre alternatif (des nœuds feuilles à la racine, puisque chaque branche est immuable). Cela peut se résumer à un énorme commutateur (sur un type de nœud), avec une gestion récursive pour chaque type de nœud. Je vais essayer de fouetter un exemple ... –

+0

merci Marc ça a marché je dois juste le faire supporter plus ExpressionType – Stacker