11using System ;
2- using System . Collections ;
32using System . Collections . Generic ;
43using System . Linq ;
54using System . Linq . Expressions ;
@@ -20,231 +19,55 @@ public static IEnumerable<StepArgument> ExtractArguments<T>(this Expression<Acti
2019 if ( methodCallExpression == null )
2120 throw new InvalidOperationException ( "Please provide a *method call* lambda expression." ) ;
2221
23- return ExtractArguments ( methodCallExpression , value , false ) ;
22+ return new ArgumentExtractorVisitor ( ) . ExtractArguments ( expression , value ) ;
2423 }
2524
2625 public static IEnumerable < StepArgument > ExtractArguments < T > ( this Expression < Func < T , Task > > expression , T value )
2726 {
28- var lambdaExpression = expression as LambdaExpression ;
29- if ( lambdaExpression == null )
30- throw new InvalidOperationException ( "Please provide a lambda expression." ) ;
31-
32- var methodCallExpression = lambdaExpression . Body as MethodCallExpression ;
33- if ( methodCallExpression == null )
34- throw new InvalidOperationException ( "Please provide a *method call* lambda expression." ) ;
35-
36- return ExtractArguments ( methodCallExpression , value , false ) ;
37- }
38-
39- private static IEnumerable < StepArgument > ExtractArguments < T > ( Expression expression , T value )
40- {
41- if ( expression == null || expression is ParameterExpression )
42- return new StepArgument [ 0 ] ;
43-
44- var memberExpression = expression as MemberExpression ;
45- if ( memberExpression != null )
46- return new [ ] { ExtractArgument ( memberExpression , value ) } ;
47-
48- var constantExpression = expression as ConstantExpression ;
49- if ( constantExpression != null )
50- return ExtractArguments ( constantExpression , value ) ;
51-
52- var newArrayExpression = expression as NewArrayExpression ;
53- if ( newArrayExpression != null )
54- return ExtractArguments ( newArrayExpression , value ) ;
55-
56- var newExpression = expression as NewExpression ;
57- if ( newExpression != null )
58- return ExtractArguments ( newExpression , value ) ;
59-
60- var unaryExpression = expression as UnaryExpression ;
61- if ( unaryExpression != null )
62- return ExtractArguments ( unaryExpression , value ) ;
63-
64- var methodCallExpression = expression as MethodCallExpression ;
65- if ( methodCallExpression != null )
66- return Invoke ( methodCallExpression , ExtractArguments ( methodCallExpression , value ) ) ;
67-
68- return new StepArgument [ 0 ] ;
69- }
70-
71- private static IEnumerable < StepArgument > Invoke ( MethodCallExpression methodCallExpression , IEnumerable < StepArgument > args )
72- {
73- var constantExpression = methodCallExpression . Object as ConstantExpression ;
74- var stepArguments = args . ToArray ( ) ;
75- if ( constantExpression != null )
76- return new [ ] { new StepArgument ( ( ) => methodCallExpression . Method . Invoke ( constantExpression . Value , stepArguments . Select ( s => s . Value ) . ToArray ( ) ) ) } ;
77-
78- return new [ ] { new StepArgument ( ( ) =>
79- {
80- var value = stepArguments . First ( ) . Value ;
81- var parameters = stepArguments . Skip ( 1 ) . Select ( s => s . Value ) . ToArray ( ) ;
82- return methodCallExpression . Method . Invoke ( value , parameters ) ;
83- } ) } ;
27+ return new ArgumentExtractorVisitor ( ) . ExtractArguments ( expression , value ) ;
8428 }
8529
86- private static IEnumerable < StepArgument > ExtractArguments < T > ( MethodCallExpression methodCallExpression , T value , bool extractArgsFromExpression = true )
30+ private class ArgumentExtractorVisitor : ExpressionVisitor
8731 {
88- var constants = new List < StepArgument > ( ) ;
89- foreach ( var arg in methodCallExpression . Arguments )
90- {
91- constants . AddRange ( ExtractArguments ( arg , value ) ) ;
92- }
32+ private List < StepArgument > _arguments ;
9333
94- if ( extractArgsFromExpression )
34+ public IEnumerable < StepArgument > ExtractArguments ( LambdaExpression methodCallExpression , object value )
9535 {
96- constants . AddRange ( ExtractArguments ( methodCallExpression . Object , value ) ) ;
36+ _arguments = new List < StepArgument > ( ) ;
37+ Visit ( methodCallExpression ) ;
38+ return _arguments ;
9739 }
9840
99- return constants ;
100- }
101-
102- private static IEnumerable < StepArgument > ExtractArguments < T > ( UnaryExpression unaryExpression , T value )
103- {
104- return ExtractArguments ( unaryExpression . Operand , value ) ;
105- }
106-
107- private static IEnumerable < StepArgument > ExtractArguments < T > ( NewExpression newExpression , T value )
108- {
109- var arguments = new List < StepArgument > ( ) ;
110- foreach ( var argumentExpression in newExpression . Arguments )
41+ protected override Expression VisitMethodCall ( MethodCallExpression node )
11142 {
112- arguments . AddRange ( ExtractArguments ( argumentExpression , value ) ) ;
113- }
114-
115- return new [ ] { new StepArgument ( ( ) => newExpression . Constructor . Invoke ( arguments . Select ( o => o . Value ) . ToArray ( ) ) ) } ;
116- }
117-
118- private static IEnumerable < StepArgument > ExtractArguments < T > ( NewArrayExpression newArrayExpression , T value )
119- {
120- Type type = newArrayExpression . Type . GetElementType ( ) ;
121- if ( type is IConvertible )
122- return ExtractConvertibleTypeArrayConstants ( newArrayExpression , type ) ;
123-
124- return ExtractNonConvertibleArrayConstants ( newArrayExpression , type , value ) ;
125- }
126-
127- private static IEnumerable < StepArgument > ExtractNonConvertibleArrayConstants < T > ( NewArrayExpression newArrayExpression , Type type , T value )
128- {
129- var arrayElements = CreateList ( type ) ;
130- foreach ( var arrayElementExpression in newArrayExpression . Expressions )
131- {
132- object arrayElement ;
133-
134- var constantExpression = arrayElementExpression as ConstantExpression ;
135- if ( constantExpression != null )
136- arrayElement = constantExpression . Value ;
137- else
138- arrayElement = ExtractArguments ( arrayElementExpression , value ) . Select ( o => o . Value ) . ToArray ( ) ;
139-
140- if ( arrayElement is object [ ] )
43+ var arguments = node . Arguments . Select ( a =>
14144 {
142- foreach ( var item in ( object [ ] ) arrayElement )
143- arrayElements . Add ( item ) ;
144- }
145- else
146- arrayElements . Add ( arrayElement ) ;
147- }
148-
149- return ToArray ( arrayElements ) . Select ( o => new StepArgument ( ( ) => o ) ) ;
150- }
151-
152- private static IEnumerable < object > ToArray ( IList list )
153- {
154- var toArrayMethod = list . GetType ( ) . GetMethod ( "ToArray" ) ;
155- yield return toArrayMethod . Invoke ( list , new Type [ ] { } ) ;
156- }
157-
158- private static IList CreateList ( Type type )
159- {
160- return ( IList ) typeof ( List < > ) . MakeGenericType ( type ) . GetConstructor ( new Type [ 0 ] ) . Invoke ( BindingFlags . CreateInstance , null , null , null ) ;
161- }
162-
163- private static IEnumerable < StepArgument > ExtractConvertibleTypeArrayConstants ( NewArrayExpression newArrayExpression , Type type )
164- {
165- var arrayElements = CreateList ( type ) ;
166- foreach ( var arrayElementExpression in newArrayExpression . Expressions )
167- {
168- var arrayElement = ( ( ConstantExpression ) arrayElementExpression ) . Value ;
169- arrayElements . Add ( Convert . ChangeType ( arrayElement , arrayElementExpression . Type , null ) ) ;
170- }
171-
172- return new [ ] { new StepArgument ( ( ) => ToArray ( arrayElements ) ) } ;
173- }
174-
175- private static IEnumerable < StepArgument > ExtractArguments < T > ( ConstantExpression constantExpression , T value )
176- {
177- var expression = constantExpression . Value as Expression ;
178- if ( expression != null )
179- {
180- return ExtractArguments ( expression , value ) ;
181- }
182-
183- var constants = new List < StepArgument > ( ) ;
184- if ( constantExpression . Type == typeof ( string ) ||
185- constantExpression . Type == typeof ( decimal ) ||
186- constantExpression . Type . IsPrimitive ||
187- constantExpression . Type . IsEnum ||
188- constantExpression . Value == null )
189- constants . Add ( new StepArgument ( ( ) => constantExpression . Value ) ) ;
190-
191- return constants ;
192- }
193-
194- private static StepArgument ExtractArgument < T > ( MemberExpression memberExpression , T value )
195- {
196- var constExpression = memberExpression . Expression as ConstantExpression ;
197- if ( constExpression != null )
198- return ExtractConstant ( memberExpression , constExpression ) ;
199-
200- var fieldInfo = memberExpression . Member as FieldInfo ;
201- if ( fieldInfo != null )
202- return ExtractFieldValue ( memberExpression , fieldInfo , value ) ;
203-
204- var propertyInfo = memberExpression . Member as PropertyInfo ;
205- if ( propertyInfo != null )
206- return ExtractPropertyValue ( memberExpression , propertyInfo , value ) ;
207-
208- throw new InvalidOperationException ( "Unknown expression type: " + memberExpression . GetType ( ) . Name ) ;
209- }
210-
211- private static StepArgument ExtractFieldValue < T > ( MemberExpression memberExpression , FieldInfo fieldInfo , T value )
212- {
213- if ( fieldInfo . IsStatic )
214- return new StepArgument ( fieldInfo , null ) ;
215-
216- return new StepArgument ( fieldInfo , value ) ;
217- }
218-
219- private static StepArgument ExtractConstant ( MemberExpression memberExpression , ConstantExpression constExpression )
220- {
221- var valIsConstant = constExpression != null ;
222- Type declaringType = memberExpression . Member . DeclaringType ;
223- object declaringObject = memberExpression . Member . DeclaringType ;
224-
225- if ( valIsConstant )
226- {
227- declaringType = constExpression . Type ;
228- declaringObject = constExpression . Value ;
45+ switch ( a . NodeType )
46+ {
47+ case ExpressionType . MemberAccess :
48+ var memberExpression = ( MemberExpression ) a ;
49+ var field = memberExpression . Member as FieldInfo ;
50+ if ( field != null )
51+ {
52+ var o = field . IsStatic ? null : GetValue ( memberExpression . Expression ) ;
53+ return new StepArgument ( field , o ) ;
54+ }
55+ var propertyInfo = ( PropertyInfo ) memberExpression . Member ;
56+ var methodInfo = propertyInfo . GetGetMethod ( true ) ;
57+ var declaringObject = methodInfo == null || methodInfo . IsStatic ? null : GetValue ( memberExpression . Expression ) ;
58+ return new StepArgument ( propertyInfo , declaringObject ) ;
59+ default :
60+ return new StepArgument ( GetValue ( a ) ) ;
61+ }
62+ } ) ;
63+ _arguments . AddRange ( arguments ) ;
64+ return node ;
22965 }
23066
231- var member = declaringType . GetMember ( memberExpression . Member . Name , MemberTypes . Field | MemberTypes . Property , BindingFlags . Public | BindingFlags . NonPublic | BindingFlags . Instance | BindingFlags . Static ) . Single ( ) ;
232-
233- if ( member . MemberType == MemberTypes . Field )
234- return new StepArgument ( ( FieldInfo ) member , declaringObject ) ;
235-
236- return new StepArgument ( ( PropertyInfo ) member , declaringObject ) ;
237- }
238-
239- private static StepArgument ExtractPropertyValue < T > ( MemberExpression expression , PropertyInfo member , T value )
240- {
241- var memberExpression = expression . Expression as MemberExpression ;
242- if ( memberExpression != null )
67+ private static Func < object > GetValue ( Expression a )
24368 {
244- var extractArguments = ExtractArgument ( memberExpression , value ) . Value ;
245- return new StepArgument ( member , extractArguments ) ;
69+ return Expression . Lambda < Func < object > > ( Expression . Convert ( a , typeof ( object ) ) ) . Compile ( ) ;
24670 }
247- return new StepArgument ( member , value ) ;
24871 }
24972 }
25073}
0 commit comments