tools/AutoMapper/XpressionMapper/Extensions/VisitorExtensions.cs (131 lines of code) (raw):

using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Runtime.CompilerServices; using AutoMapper.XpressionMapper.Structures; namespace AutoMapper.XpressionMapper.Extensions { using AutoMapper.Internal; using Configuration; internal static class VisitorExtensions { /// <summary> /// Returns true if the expression is a direct or descendant member expression of the parameter. /// </summary> /// <param name="expression"></param> /// <returns></returns> public static bool IsMemberExpression(this Expression expression) { if (expression.NodeType == ExpressionType.MemberAccess) { var memberExpression = (MemberExpression)expression; return IsMemberOrParameterExpression(memberExpression.Expression); } return false; } private static bool IsMemberOrParameterExpression(Expression expression) { //the node represents parameter of the expression switch (expression.NodeType) { case ExpressionType.Parameter: return true; case ExpressionType.MemberAccess: var memberExpression = (MemberExpression)expression; return IsMemberOrParameterExpression(memberExpression.Expression); } return false; } /// <summary> /// Returns the fully qualified name of the member starting with the immediate child member of the parameter /// </summary> /// <param name="expression"></param> /// <returns></returns> public static string GetPropertyFullName(this Expression expression) { const string period = "."; //the node represents parameter of the expression switch (expression.NodeType) { case ExpressionType.Parameter: return string.Empty; case ExpressionType.MemberAccess: var memberExpression = (MemberExpression)expression; var parentFullName = memberExpression.Expression.GetPropertyFullName(); return string.IsNullOrEmpty(parentFullName) ? memberExpression.Member.Name : string.Concat(memberExpression.Expression.GetPropertyFullName(), period, memberExpression.Member.Name); } throw new InvalidOperationException(Resource.invalidExpErr); } private static MemberExpression GetMemberExpression(LambdaExpression expr) { MemberExpression me; switch (expr.Body.NodeType) { case ExpressionType.Convert: case ExpressionType.ConvertChecked: var ue = expr.Body as UnaryExpression; me = ue?.Operand as MemberExpression; break; default: me = expr.Body as MemberExpression; if (me == null) { if (expr.Body is BinaryExpression binaryExpression) { if (binaryExpression.Left is MemberExpression left) return left; if (binaryExpression.Right is MemberExpression right) return right; } } break; } return me; } /// <summary> /// Returns the ParameterExpression for the LINQ parameter. /// </summary> /// <param name="expression"></param> /// <returns></returns> public static ParameterExpression GetParameterExpression(this Expression expression) { if (expression == null) return null; //the node represents parameter of the expression switch (expression.NodeType) { case ExpressionType.Parameter: return (ParameterExpression)expression; case ExpressionType.Quote: return GetParameterExpression(GetMemberExpression((LambdaExpression)((UnaryExpression)expression).Operand)); case ExpressionType.Lambda: return GetParameterExpression(GetMemberExpression((LambdaExpression)expression)); case ExpressionType.ConvertChecked: case ExpressionType.Convert: var ue = expression as UnaryExpression; return GetParameterExpression(ue?.Operand); case ExpressionType.MemberAccess: return GetParameterExpression(((MemberExpression)expression).Expression); case ExpressionType.Call: var methodExpression = expression as MethodCallExpression; var memberExpression = methodExpression?.Object as MemberExpression;//Method is an instance method var isExtension = methodExpression != null && methodExpression.Method.IsDefined(typeof(ExtensionAttribute), true); if (isExtension && memberExpression == null && methodExpression.Arguments.Count > 0) memberExpression = methodExpression.Arguments[0] as MemberExpression;//Method is an extension method based on the type of methodExpression.Arguments[0] and methodExpression.Arguments[0] is a member expression. return isExtension && memberExpression == null && methodExpression.Arguments.Count > 0 ? GetParameterExpression(methodExpression.Arguments[0]) : (memberExpression == null ? null : GetParameterExpression(memberExpression.Expression)); } return null; } /// <summary> /// Adds member expressions to an existing expression. /// </summary> /// <param name="exp"></param> /// <param name="list"></param> /// <returns></returns> public static MemberExpression MemberAccesses(this Expression exp, List<PropertyMapInfo> list) => (MemberExpression) list.SelectMany(propertyMapInfo => propertyMapInfo.DestinationPropertyInfos).MemberAccesses(exp); /// <summary> /// For the given a Lambda Expression, returns the fully qualified name of the member starting with the immediate child member of the parameter /// </summary> /// <param name="expr"></param> /// <returns></returns> public static string GetMemberFullName(this LambdaExpression expr) { if (expr.Body.NodeType == ExpressionType.Parameter) return string.Empty; MemberExpression me; switch (expr.Body.NodeType) { case ExpressionType.Convert: case ExpressionType.ConvertChecked: me = (expr.Body as UnaryExpression)?.Operand as MemberExpression; break; default: me = expr.Body as MemberExpression; break; } return me.GetPropertyFullName(); } /// <summary> /// Returns the underlying type typeof(T) when the type implements IEnumerable. /// </summary> /// <param name="type"></param> /// <returns></returns> public static List<Type> GetUnderlyingGenericTypes(this Type type) => type == null || !type.GetTypeInfo().IsGenericType ? new List<Type>() : type.GetGenericArguments().ToList(); } }