Convertir les arbres d'expression

c# expression-trees lambda linq-to-sql

Question

qu'il y ait :

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); le problème est que je n'ai que exp2, j'ai besoin de convertir le type en Message, toutes les propriétés sont les mêmes!

maintenant je fais ça:

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

Le problème, c'est que le paramètre d'entrée est modifié, oui! mais le x à l'intérieur du corps du lambda "x.mesID" est du type ancien.

un moyen de changer tous les types de paramètres dans le corps aussi ou de changer le paramètre d'entrée pour qu'il reflète le corps aussi?

J'imagine que c'est un gros problème que j'ai toujours avec LINQ, car entre les couches, je ne peux pas transmettre les classes générées, car cela créera des couches couplées. .où(); de la couche de busiess? !! Bien que la couche busniess ne sache rien sur le type de message, elle ne connaît que MessageDTO.

Réponse acceptée

Non, fondamentalement. Les arbres d'expression sont immuables et contiennent les méta-données de membre complet (c'est-à-dire que mesID est messageDTO.mesID ). Pour ce faire, vous devez reconstruire l’arbre d’expression à partir de zéro (via un visiteur), en gérant tous les types de nœuds à prendre en charge.

Si l'arborescence des expressions est basique, cela devrait être correct, mais si vous devez prendre en charge toute la gamme? un énorme PITA (en particulier dans .NET 4, qui ajoute beaucoup plus de types de nœuds).


Un exemple de base qui fait exactement ce qui est requis pour l'exemple; vous auriez besoin d'ajouter plus de types de nœuds pour des 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; } }



Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi