@@ -18,7 +18,7 @@ type ObjectListFilter =
18
18
| In of FieldFilter < System.IComparable list >
19
19
| StartsWith of FieldFilter < string >
20
20
| EndsWith of FieldFilter < string >
21
- | Contains of FieldFilter < string >
21
+ | Contains of FieldFilter < System.IComparable >
22
22
| OfTypes of Type list
23
23
| FilterField of FieldFilter < ObjectListFilter >
24
24
@@ -142,25 +142,27 @@ module ObjectListFilter =
142
142
let private StringStartsWithMethod = stringType.GetMethod ( " StartsWith" , [| stringType |])
143
143
let private StringEndsWithMethod = stringType.GetMethod ( " EndsWith" , [| stringType |])
144
144
let private StringContainsMethod = stringType.GetMethod ( " Contains" , [| stringType |])
145
- let private getEnumerableContainsMethod ( memberType : Type ) =
145
+ let private getCollectionInstanceContainsMethod ( memberType : Type ) =
146
+ memberType
147
+ .GetMethods( BindingFlags.Instance ||| BindingFlags.Public)
148
+ .FirstOrDefault ( fun m -> m.Name = " Contains" && m.GetParameters() .Length = 1 )
149
+ |> ValueOption.ofObj
150
+ let private getEnumerableContainsMethod ( itemType : Type ) =
146
151
match
147
152
typeof< Enumerable>
148
153
.GetMethods( BindingFlags.Static ||| BindingFlags.Public)
149
154
.FirstOrDefault ( fun m -> m.Name = " Contains" && m.GetParameters() .Length = 2 )
150
155
with
151
156
| null -> raise ( MissingMemberException " Static 'Contains' method with 2 parameters not found on 'Enumerable' class" )
152
- | containsGenericStaticMethod ->
153
- if
154
- memberType.IsGenericType
155
- && memberType.GenericTypeArguments.Length = 1
156
- then
157
- containsGenericStaticMethod.MakeGenericMethod ( memberType.GenericTypeArguments)
158
- else
159
- let ienumerable =
160
- memberType
161
- .GetInterfaces()
162
- .First ( fun i -> i.FullName.StartsWith " System.Collections.Generic.IEnumerable`1" )
163
- containsGenericStaticMethod.MakeGenericMethod ([| ienumerable.GenericTypeArguments[ 0 ] |])
157
+ | containsGenericStaticMethod -> containsGenericStaticMethod.MakeGenericMethod ([| itemType |])
158
+ let private getEnumerableCastMethod ( itemType : Type ) =
159
+ match
160
+ typeof< Enumerable>
161
+ .GetMethods( BindingFlags.Static ||| BindingFlags.Public)
162
+ .FirstOrDefault ( fun m -> m.Name = " Cast" && m.GetParameters() .Length = 1 )
163
+ with
164
+ | null -> raise ( MissingMemberException " Static 'Cast' method with 1 parameter not found on 'Enumerable' class" )
165
+ | castGenericStaticMethod -> castGenericStaticMethod.MakeGenericMethod ([| itemType |])
164
166
165
167
let getField ( param : ParameterExpression ) fieldName = Expression.PropertyOrField ( param, fieldName)
166
168
@@ -204,38 +206,38 @@ module ObjectListFilter =
204
206
&& memberType
205
207
.GetInterfaces()
206
208
.Any ( fun i -> i.FullName.StartsWith " System.Collections.Generic.IEnumerable`1" )
209
+ let callContains memberType =
210
+ let itemType =
211
+ if `` member `` .Type.IsArray then `` member `` .Type.GetElementType()
212
+ else `` member `` .Type.GetGenericArguments()[ 0 ]
213
+ let valueType =
214
+ match f.Value with
215
+ | null -> itemType
216
+ | value -> value.GetType()
217
+ let castedMember =
218
+ if itemType = valueType then `` member `` :> Expression
219
+ else
220
+ let castMethod = getEnumerableCastMethod valueType
221
+ Expression.Call ( castMethod, `` member `` )
222
+ match getCollectionInstanceContainsMethod memberType with
223
+ | ValueNone ->
224
+ let enumerableContains = getEnumerableContainsMethod valueType
225
+ Expression.Call ( enumerableContains, castedMember, Expression.Constant ( f.Value))
226
+ | ValueSome instanceContainsMethod ->
227
+ Expression.Call ( castedMember, instanceContainsMethod, Expression.Constant ( f.Value))
207
228
match `` member `` .Member with
208
- | :? PropertyInfo as prop when prop.PropertyType |> isEnumerable ->
209
- match
210
- prop.PropertyType
211
- .GetMethods( BindingFlags.Instance ||| BindingFlags.Public)
212
- .FirstOrDefault ( fun m -> m.Name = " Contains" && m.GetParameters() .Length = 1 )
213
- with
214
- | null ->
215
- Expression.Call (
216
- getEnumerableContainsMethod prop.PropertyType,
217
- Expression.PropertyOrField ( param, f.FieldName),
218
- Expression.Constant ( f.Value)
219
- )
220
- | instanceContainsMethod ->
221
- Expression.Call ( Expression.PropertyOrField ( param, f.FieldName), instanceContainsMethod, Expression.Constant ( f.Value))
222
- | :? FieldInfo as field when field.FieldType |> isEnumerable ->
223
- Expression.Call (
224
- getEnumerableContainsMethod field.FieldType,
225
- Expression.PropertyOrField ( param, f.FieldName),
226
- Expression.Constant ( f.Value)
227
- )
229
+ | :? PropertyInfo as prop when prop.PropertyType |> isEnumerable -> callContains prop.PropertyType
230
+ | :? FieldInfo as field when field.FieldType |> isEnumerable -> callContains field.FieldType
228
231
| _ ->
229
232
if `` member `` .Type = stringType then
230
233
Expression.Call ( `` member `` , StringContainsMethod, Expression.Constant ( f.Value))
231
234
else
232
235
Expression.Call ( Expression.Convert ( `` member `` , stringType), StringContainsMethod, Expression.Constant ( f.Value))
233
- | In f ->
236
+ | In f when not ( f.Value.IsEmpty ) ->
234
237
let ``member`` = Expression.PropertyOrField ( param, f.FieldName)
235
- f.Value
236
- |> Seq.map ( fun v -> Expression.Equal ( `` member `` , Expression.Constant ( v)))
237
- |> Seq.reduce ( fun acc expr -> Expression.OrElse ( acc, expr))
238
- :> Expression
238
+ let enumerableContains = getEnumerableContainsMethod typeof< IComparable>
239
+ Expression.Call ( enumerableContains, Expression.Constant ( f.Value), Expression.Convert ( `` member `` , typeof< IComparable>))
240
+ | In f -> Expression.Constant ( true )
239
241
| OfTypes types ->
240
242
types
241
243
|> Seq.map ( fun t -> buildTypeDiscriminatorCheck param t)
0 commit comments