Konvertieren von Ausdrucksbäumen

c# expression-trees lambda linq-to-sql

Frage

lass es sein:

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

Jetzt muss ich exp1 zu _db.Messages.where(exp1); Problem ist, ich habe nur exp2, ich muss den Typ in Nachricht konvertieren, Alle Eigenschaften sind gleich!

jetzt mache ich das:

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

Problem damit ist der Eingangsparameter wird ja geändert! aber das x innerhalb des Körpers des Lambda "x.mesID" ist vom alten Typ.

Wie auch immer, um alle Parameter im Körper zu ändern oder den Eingabeparameter zu ändern, spiegelt es auch den Körper wider?

Ich denke, das ist ein großes Problem, das ich immer mit LINQ habe, da ich zwischen den Ebenen die generierten Klassen nicht weitergeben kann, da dies Schichten gekoppelt macht, also muss ich leichte Gewichtsklassen machen, wie verwende ich nun eine Methode wie _db.Messages .woher(); von Business-Schicht? !! Während Busniess Layer nichts über Nachrichtentyp weiß, kennt sie nur MessageDTO.

Akzeptierte Antwort

Nein, im Grunde genommen. Ausdrucksbäume sind unveränderlich und enthalten vollständige Mitglieder-Metadaten (dh diese mesID ist messageDTO.mesID ). Um dies zu tun, müssten Sie den Ausdrucksbaum von Grund auf neu erstellen (über einen Besucher) und jeden Knoten-Typ behandeln, den Sie unterstützen müssen.

Wenn der Ausdruck Baum Grund ist , sollte dies in Ordnung sein, aber wenn man das gesamte Spektrum unterstützen müssen? eine riesige PITA (besonders in .NET 4, die viel mehr Knotentypen hinzufügt).


Ein grundlegendes Beispiel, das genau das tut, was für das Beispiel erforderlich ist; Sie müssten mehr Knotentypen für komplexere Ausdrücke hinzufügen:

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; } }



Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Ist diese KB legal? Ja, lerne warum
Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Ist diese KB legal? Ja, lerne warum