Convert Expression trees

前端 未结 1 436
暖寄归人
暖寄归人 2021-01-04 11:45

let there be :

Expression> exp1 = x => x.mesID == 1;
Expression> exp2 = x => x.mesID         


        
相关标签:
1条回答
  • 2021-01-04 12:08

    No, basically. Expression trees are immutable, and contain full member meta-data (i.e. that mesID is messageDTO.mesID). To do this, you would have to rebuild the expression tree from scratch (via a visitor), handling every node type you need to support.

    If the expression tree is basic this should be OK, but if you need to support the entire gamut? a huge PITA (especially in .NET 4, which adds a lot more node-types).


    A basic example that does just what is required for the example; you would need to add more node-types for more complex expressions:

    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 讨论(0)
提交回复
热议问题