为嵌套模型翻译表达式树

时间:2014-06-22 20:03:00

标签: c# linq lambda expression-trees

我有表达式树转换器,它将表达式从一个类型转换为另一个类型,我也有这样的嵌套模型:

public class Person
{
    public string Name { get; set; }

    public int Age { get; set; }

    public DateTime JoiningDate { get; set; }

    public IList<Ticket> Tickets { get; set; }
}

我有这个班的Dto:

public class PersonDto
{
    public string Name { get; set; }

    public int Age { get; set; }

    public DateTime JoiningDate { get; set; }

    public IList<TicketDto> Tickets { get; set; }
}

这是我的转换器的代码:

public static class ExpressionConverter<TEntity> where TEntity : class
{
    public static Expression<Func<TEntity, TType>> Convert<TDto, TType>(Expression<Func<TDto, TType>> expression)
    {
        if (expression == null)
        {
            return (null);
        }

        var newParameter = Expression.Parameter(typeof(TEntity), "ent");

        var converter = new ConversionVisitor(newParameter);

        var bodyExpression = converter.Visit(expression.Body);
        var lambdaExpression = Expression.Lambda<Func<TEntity, TType>>(bodyExpression, newParameter);

        return (lambdaExpression);
    }

    #region ConversionVisitor Nested Class

    private sealed class ConversionVisitor : ExpressionVisitor
    {
        private readonly ParameterExpression _newParameter;

        public ConversionVisitor(ParameterExpression newParameter)
        {
            _newParameter = newParameter;
        }

        #region Overrides

        protected override Expression VisitParameter(ParameterExpression node)
        {
            return (_newParameter);
        }

        protected override Expression VisitMember(MemberExpression node)
        {
            var newExpression = Visit(node.Expression);
            var newMemberInfo = newExpression.Type.GetMember(node.Member.Name).First();
            var newMemberExpression = Expression.MakeMemberAccess(newExpression, newMemberInfo);

            return (newMemberExpression);
        }

        protected override Expression VisitBinary(BinaryExpression node)
        {
            MemberExpression memberExpression;
            Expression leftExpression;

            var binaryExpression = node.Right as BinaryExpression;
            if (binaryExpression != null)
            {
                leftExpression = binaryExpression.Left;
            }
            else
            {
                var constantExpression = node.Right as ConstantExpression;
                if (constantExpression != null)
                {
                    leftExpression = node.Left;
                }
                else
                {
                    var unaryExpression = node.Right as UnaryExpression;
                    if (unaryExpression != null)
                    {
                        leftExpression = unaryExpression.Operand;
                    }
                    else
                    {
                        return (base.VisitBinary(node));
                    }
                }
            }

            if (leftExpression is MethodCallExpression)
            {
                return (base.VisitBinary(node));
            }
            if (leftExpression is BinaryExpression)
            {
                return (base.VisitBinary(node));
            }

            var leftUnaryExpression = leftExpression as UnaryExpression;
            if (leftUnaryExpression != null)
            {
                memberExpression = (MemberExpression)leftUnaryExpression.Operand;
            }
            else
            {
                var leftMemberExpression = leftExpression as MemberExpression;
                if (leftMemberExpression != null)
                {
                    memberExpression = leftMemberExpression;
                }
                else
                {
                    throw new ArgumentException("Ouch Disable Shodim");
                }
            }

            var memberInfo = memberExpression.Member;
            if (memberInfo == null)
            {
                throw new Exception("memberInfo");
            }
            return (base.VisitBinary(node));
        }

        #endregion Overrides
    }

    #endregion ConversionVisitor Nested Class
}

当我有这样的表达时

Expression<Func<PersonModel, bool>> expr = p => p.Age == 29 && p.Tickets.Any(t => t.Id == 1);

我的转换器无法转换Ticket的正确表达式部分,因为转换器不知道Ticket的类型。有没有办法解决这个问题?我正在寻找转换器可以将N级挖掘到模型中的解决方案。

0 个答案:

没有答案