1- using System ;
1+ using AutoMapper . Extensions . ExpressionMapping . Structures ;
2+ using AutoMapper . Internal ;
3+ using System ;
24using System . Collections . Generic ;
35using System . Linq ;
46using System . Linq . Expressions ;
57using System . Reflection ;
6- using AutoMapper . Internal ;
8+ using System . Runtime . CompilerServices ;
79
810namespace AutoMapper . Extensions . ExpressionMapping
911{
1012 using static Expression ;
1113
1214 internal static class ExpressionExtensions
1315 {
14- public static Expression MemberAccesses ( this IEnumerable < MemberInfo > members , Expression obj ) =>
15- members . Aggregate ( obj , ( expression , member ) => MakeMemberAccess ( expression , member ) ) ;
16- }
16+ public static Expression ConvertTypeIfNecessary ( this Expression expression , Type memberType )
17+ {
18+ if ( memberType == expression . Type )
19+ return expression ;
1720
18- internal static class ExpressionHelpers
19- {
20- public static MemberExpression MemberAccesses ( string members , Expression obj ) =>
21- ( MemberExpression ) GetMemberPath ( obj . Type , members ) . MemberAccesses ( obj ) ;
21+ expression = expression . GetUnconvertedExpression ( ) ;
22+ if ( memberType != expression . Type )
23+ return Expression . Convert ( expression , memberType ) ;
24+
25+ return expression ;
26+ }
27+
28+ /// <summary>
29+ /// Returns the first ancestor node that is not a MemberExpression.
30+ /// </summary>
31+ /// <param name="expression"></param>
32+ /// <returns></returns>
33+ public static Expression GetBaseOfMemberExpression ( this MemberExpression expression )
34+ {
35+ if ( expression . Expression == null )
36+ return null ;
37+
38+ return expression . Expression . NodeType == ExpressionType . MemberAccess
39+ ? GetBaseOfMemberExpression ( ( MemberExpression ) expression . Expression )
40+ : expression . Expression ;
41+ }
42+
43+ public static MemberExpression GetMemberExpression ( this Expression expr )
44+ => expr ? . GetUnconvertedExpression ( ) as MemberExpression ;
45+
46+ public static MemberExpression GetMemberExpression ( this LambdaExpression expr )
47+ => expr . Body . GetUnconvertedExpression ( ) as MemberExpression ;
2248
23- public static Expression ReplaceParameters ( this LambdaExpression exp , params Expression [ ] replace )
49+ /// <summary>
50+ /// For the given a Lambda Expression, returns the fully qualified name of the member starting with the immediate child member of the parameter
51+ /// </summary>
52+ /// <param name="expr"></param>
53+ /// <returns></returns>
54+ public static string GetMemberFullName ( this LambdaExpression expr )
2455 {
25- var replaceExp = exp . Body ;
26- for ( var i = 0 ; i < Math . Min ( replace . Length , exp . Parameters . Count ) ; i ++ )
27- replaceExp = Replace ( replaceExp , exp . Parameters [ i ] , replace [ i ] ) ;
28- return replaceExp ;
56+ if ( expr . Body . NodeType == ExpressionType . Parameter )
57+ return string . Empty ;
58+ MemberExpression me = expr . Body . NodeType switch
59+ {
60+ ExpressionType . Convert or ExpressionType . ConvertChecked or ExpressionType . TypeAs => expr . Body . GetUnconvertedExpression ( ) as MemberExpression ,
61+ _ => expr . Body as MemberExpression ,
62+ } ;
63+ return me . GetPropertyFullName ( ) ;
2964 }
3065
31- public static Expression Replace ( this Expression exp , Expression old , Expression replace ) => new ReplaceExpressionVisitor ( old , replace ) . Visit ( exp ) ;
66+ /// <summary>
67+ /// Returns the ParameterExpression for the LINQ parameter.
68+ /// </summary>
69+ /// <param name="expression"></param>
70+ /// <returns></returns>
71+ public static ParameterExpression GetParameterExpression ( this Expression expression )
72+ {
73+ if ( expression == null )
74+ return null ;
75+
76+ //the node represents parameter of the expression
77+ switch ( expression . NodeType )
78+ {
79+ case ExpressionType . Parameter :
80+ return ( ParameterExpression ) expression ;
81+ case ExpressionType . Quote :
82+ return GetParameterExpression ( ( ( UnaryExpression ) expression ) . Operand ) ;
83+ case ExpressionType . Lambda :
84+ return GetParameterExpression ( ( ( LambdaExpression ) expression ) . Body ) ;
85+ case ExpressionType . ConvertChecked :
86+ case ExpressionType . Convert :
87+ var ue = expression as UnaryExpression ;
88+ return GetParameterExpression ( ue ? . Operand ) ;
89+ case ExpressionType . TypeAs :
90+ return ( ( UnaryExpression ) expression ) . Operand . GetParameterExpression ( ) ;
91+ case ExpressionType . TypeIs :
92+ return ( ( TypeBinaryExpression ) expression ) . Expression . GetParameterExpression ( ) ;
93+ case ExpressionType . MemberAccess :
94+ return GetParameterExpression ( ( ( MemberExpression ) expression ) . Expression ) ;
95+ case ExpressionType . Call :
96+ var methodExpression = expression as MethodCallExpression ;
97+ var parentExpression = methodExpression ? . Object ; //Method is an instance method
98+
99+ var isExtension = methodExpression != null && methodExpression . Method . IsDefined ( typeof ( ExtensionAttribute ) , true ) ;
100+ if ( isExtension && parentExpression == null && methodExpression . Arguments . Count > 0 )
101+ parentExpression = methodExpression . Arguments [ 0 ] ; //Method is an extension method based on the type of methodExpression.Arguments[0].
102+
103+ if ( parentExpression == null )
104+ return null ;
32105
33- private static IEnumerable < MemberInfo > GetMemberPath ( Type type , string fullMemberName )
106+ return GetParameterExpression ( parentExpression ) ;
107+ }
108+
109+ return null ;
110+ }
111+
112+ /// <summary>
113+ /// Returns the fully qualified name of the member starting with the immediate child member of the parameter
114+ /// </summary>
115+ /// <param name="expression"></param>
116+ /// <returns></returns>
117+ public static string GetPropertyFullName ( this Expression expression )
34118 {
35- MemberInfo property = null ;
36- foreach ( var memberName in fullMemberName . Split ( '.' ) )
119+ if ( expression == null )
120+ return string . Empty ;
121+
122+ const string period = "." ;
123+
124+ //the node represents parameter of the expression
125+ switch ( expression . NodeType )
37126 {
38- var currentType = GetCurrentType ( property , type ) ;
39- yield return property = currentType . GetFieldOrProperty ( memberName ) ;
127+ case ExpressionType . MemberAccess :
128+ var memberExpression = ( MemberExpression ) expression ;
129+ var parentFullName = memberExpression . Expression . GetPropertyFullName ( ) ;
130+ return string . IsNullOrEmpty ( parentFullName )
131+ ? memberExpression . Member . Name
132+ : string . Concat ( memberExpression . Expression . GetPropertyFullName ( ) , period , memberExpression . Member . Name ) ;
133+ default :
134+ return string . Empty ;
40135 }
41136 }
42137
43- private static Type GetCurrentType ( MemberInfo member , Type type )
44- => member ? . GetMemberType ( ) ?? type ;
138+ public static Expression GetUnconvertedExpression ( this Expression expression )
139+ {
140+ return expression . NodeType switch
141+ {
142+ ExpressionType . Convert or ExpressionType . ConvertChecked or ExpressionType . TypeAs => ( ( UnaryExpression ) expression ) . Operand . GetUnconvertedExpression ( ) ,
143+ _ => expression ,
144+ } ;
145+ }
146+
147+ /// <summary>
148+ /// Determines whether the specified type is an enumeration type.
149+ /// </summary>
150+ /// <param name="type">The type to evaluate. This can be a nullable type, in which case the underlying type is checked.</param>
151+ /// <returns>true if the specified type is an enumeration; otherwise, false.</returns>
152+ public static bool IsEnumType ( this Type type )
153+ {
154+ if ( type . IsNullableType ( ) )
155+ type = Nullable . GetUnderlyingType ( type ) ;
156+
157+ return type . IsEnum ( ) ;
158+ }
159+
160+ /// <summary>
161+ /// Adds member expressions to an existing expression.
162+ /// </summary>
163+ /// <param name="exp"></param>
164+ /// <param name="list"></param>
165+ /// <returns></returns>
166+ public static MemberExpression MemberAccesses ( this Expression exp , List < PropertyMapInfo > list ) =>
167+ ( MemberExpression ) list . SelectMany ( propertyMapInfo => propertyMapInfo . DestinationPropertyInfos ) . MemberAccesses ( exp ) ;
168+
169+ public static Expression MemberAccesses ( this IEnumerable < MemberInfo > members , Expression obj ) =>
170+ members . Aggregate ( obj , MakeMemberAccess ) ;
45171 }
46172}
0 commit comments