แปลงต้นไม้นิพจน์

ให้มี:

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

ตอนนี้ฉันต้องส่ง exp1 ถึง _db.Messages.where(exp1); ปัญหาคือฉันมีเพียง exp2 เท่านั้น ฉันต้องแปลงประเภทเป็น Message คุณสมบัติทั้งหมดเหมือนกัน !

ตอนนี้ฉันทำสิ่งนี้:

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

ปัญหานี้คือพารามิเตอร์อินพุตได้รับการเปลี่ยนแปลงใช่ ! แต่ x ภายในเนื้อความของแลมบ์ดา "x.mesID" นั้นเป็นแบบเก่า

มีวิธีใดที่จะเปลี่ยนประเภทพารามิเตอร์ทั้งหมดในร่างกายด้วยหรือเปลี่ยนพารามิเตอร์อินพุตออกไปมันก็สะท้อนถึงร่างกายด้วย

ฉันเดาว่านี่เป็นปัญหาใหญ่ที่ฉันมีกับ LINQ เสมอ เนื่องจากระหว่างเลเยอร์ฉันไม่สามารถผ่านคลาสที่สร้างขึ้นได้ เนื่องจากจะทำให้เลเยอร์เชื่อมโยงกัน ดังนั้นฉันต้องสร้างคลาสน้ำหนักเบา ตอนนี้ฉันจะใช้วิธีการเช่น _db.Messages ได้อย่างไร .ที่ไหน(); จากชั้นยุ่งเหรอ?!! ในขณะที่ชั้นธุรกิจไม่รู้อะไรเกี่ยวกับประเภทข้อความ แต่รู้แค่ MessageDTO เท่านั้น


person Stacker    schedule 08.09.2010    source แหล่งที่มา


คำตอบ (1)


ไม่ โดยพื้นฐานแล้ว แผนผังนิพจน์ไม่เปลี่ยนรูปและมีข้อมูลเมตาของสมาชิกแบบเต็ม (เช่น mesID คือ messageDTO.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; } }
person Marc Gravell    schedule 08.09.2010
comment
via vistor คุณหมายถึงอะไร? คุณช่วยยกตัวอย่างให้ฉันหน่อยได้ไหม? - person Stacker; 08.09.2010
comment
การใช้งานของผู้เยี่ยมชม เช่น โครงสร้างโค้ดบางตัวที่คุณใช้สำรวจโครงสร้างต้นไม้ทั้งหมด โดยทั่วไปแล้วจะสร้างต้นไม้ทางเลือก (จากโหนดใบกลับไปยังราก เนื่องจากแต่ละกิ่งไม่เปลี่ยนรูป) สิ่งนี้อาจทำให้สวิตช์ขนาดใหญ่ (บนประเภทโหนด) โดยมีการจัดการแบบเรียกซ้ำสำหรับโหนดแต่ละประเภท ฉันจะพยายามยกตัวอย่าง... - person Marc Gravell; 08.09.2010
comment
ขอบคุณ Marc มันใช้งานได้ ฉันแค่ต้องทำให้มันรองรับ ExpressionType มากขึ้น - person Stacker; 08.09.2010
comment
@Stacker - นั่นคือความสนุก ;p โปรดทราบว่าคุณควรจะสามารถนำชิ้นส่วนขนาดใหญ่กลับมาใช้ใหม่ได้ ตัวอย่างเช่น นิพจน์ไบนารีส่วนใหญ่ควรใช้ตัวอย่างที่มีอยู่ได้ - person Marc Gravell; 08.09.2010
comment
มีคำถามเดียวที่ฉันมีสำหรับคุณ คุณจะจัดการกรณี ExpressionType.Convert อย่างไร: - person Stacker; 15.09.2010
comment
@MarcGravell คุณมีความคิดเกี่ยวกับ ExpressionType.New บ้างไหม? - person Vahid Farahmandian; 14.04.2019