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