using Masuit.Tools.Mapping.Core; using System; using System.Collections.Generic; using System.Linq.Expressions; namespace Masuit.Tools.Mapping.Visitor { /// /// 将表达式从源转换为目标的访问者表达式 /// public class ConverterExpressionVisitor : ExpressionVisitor { private readonly Dictionary _parameterMap; private readonly Type _destinationType; private MapperConfigurationBase _mapper; /// /// 构造函数 /// /// /// public ConverterExpressionVisitor(Dictionary parameterMap, Type typeDestination) { _parameterMap = parameterMap; _destinationType = typeDestination; } /// /// /// /// 访问表达式树 /// /// 改变表达式,如果它或它的任何子表达式被修改; 否则,返回原始表达式。 /// protected override Expression VisitParameter(ParameterExpression node) { if (!_parameterMap.TryGetValue(node, out var found)) { found = Expression.Parameter(_destinationType, "dest"); } return found; } /// /// 将表达式分布在此类中更专业的访问方法之一。 /// /// 访问表达式树 /// /// 改变表达式,如果它或它的任何子表达式被修改; 否则,返回原始表达式。 /// public override Expression Visit(Expression node) { if (node != null) { return node.NodeType switch { ExpressionType.Lambda => base.Visit((node as LambdaExpression).Body), _ => base.Visit(node) }; } return node; } /// /// 访问子表达式树 /// /// 访问表达式树 /// /// 改变表达式,如果它或它的任何子表达式被修改; 否则,返回原始表达式。 /// protected override Expression VisitMember(MemberExpression node) { var expr = Visit(node.Expression); if (expr != null && expr.Type != node.Type) { if (_mapper == null) { _mapper = ExpressionMapper.GetMapper(node.Member.DeclaringType, _destinationType); } Expression expDest; // 认为原始类是简单属性(不是子对象)。 if (!expr.Type.IsValueType && expr.Type != typeof(string) && expr.NodeType != ExpressionType.Parameter && expr.NodeType != ExpressionType.Constant) { var subExp = ExpressionMapper.GetMapper(node.Member.DeclaringType, expr.Type); expDest = subExp.GetLambdaDest(node.Member.Name); return AnalyseDestExpression(expr, expDest); } expDest = _mapper.GetLambdaDest(node.Member.Name); if (expDest != null) { return AnalyseDestExpression(expr, expDest); } } return base.VisitMember(node); } private Expression AnalyseDestExpression(Expression expr, Expression expDest) { return expDest.NodeType == ExpressionType.MemberAccess ? Expression.MakeMemberAccess(expr, (expDest as MemberExpression).Member) : base.Visit(expDest); } } }