1
1
using System ;
2
- using System . Collections ;
3
2
using System . Collections . Generic ;
4
3
using System . Linq ;
5
4
using System . Linq . Expressions ;
@@ -20,231 +19,55 @@ public static IEnumerable<StepArgument> ExtractArguments<T>(this Expression<Acti
20
19
if ( methodCallExpression == null )
21
20
throw new InvalidOperationException ( "Please provide a *method call* lambda expression." ) ;
22
21
23
- return ExtractArguments ( methodCallExpression , value , false ) ;
22
+ return new ArgumentExtractorVisitor ( ) . ExtractArguments ( expression , value ) ;
24
23
}
25
24
26
25
public static IEnumerable < StepArgument > ExtractArguments < T > ( this Expression < Func < T , Task > > expression , T value )
27
26
{
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 ) ;
84
28
}
85
29
86
- private static IEnumerable < StepArgument > ExtractArguments < T > ( MethodCallExpression methodCallExpression , T value , bool extractArgsFromExpression = true )
30
+ private class ArgumentExtractorVisitor : ExpressionVisitor
87
31
{
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 ;
93
33
94
- if ( extractArgsFromExpression )
34
+ public IEnumerable < StepArgument > ExtractArguments ( LambdaExpression methodCallExpression , object value )
95
35
{
96
- constants . AddRange ( ExtractArguments ( methodCallExpression . Object , value ) ) ;
36
+ _arguments = new List < StepArgument > ( ) ;
37
+ Visit ( methodCallExpression ) ;
38
+ return _arguments ;
97
39
}
98
40
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 )
111
42
{
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 =>
141
44
{
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 ;
229
65
}
230
66
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 )
243
68
{
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 ( ) ;
246
70
}
247
- return new StepArgument ( member , value ) ;
248
71
}
249
72
}
250
73
}
0 commit comments