让:

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

问题是输入参数被更改是的!但是lambda“x.mesID”主体内的x是旧类型。

任何方式也可以更改主体中的所有参数类型,或者也可以更改输入参数以使其完全反射(reflect)主体?

我想这是LINQ经常遇到的一个大问题,因为在各层之间我无法传递生成的类,因为这会使各层耦合,所以我必须制作轻量级的类,现在我该如何使用类似_db.Messages的方法。在哪里();从繁忙的图层?虽然busniess层对消息类型一无所知,但仅知道MessageDTO。

最佳答案

不,基本上。表达式树是不可变的,并且包含完整的成员元数据(即mesIDmessageDTO.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; } }

10-06 14:01