@@ -18,7 +18,7 @@ type ObjectListFilter =
1818 | In of FieldFilter < System.IComparable list >
1919 | StartsWith of FieldFilter < string >
2020 | EndsWith of FieldFilter < string >
21- | Contains of FieldFilter < string >
21+ | Contains of FieldFilter < System.IComparable >
2222 | OfTypes of Type list
2323 | FilterField of FieldFilter < ObjectListFilter >
2424
@@ -142,25 +142,27 @@ module ObjectListFilter =
142142 let private StringStartsWithMethod = stringType.GetMethod ( " StartsWith" , [| stringType |])
143143 let private StringEndsWithMethod = stringType.GetMethod ( " EndsWith" , [| stringType |])
144144 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 ) =
146151 match
147152 typeof< Enumerable>
148153 .GetMethods( BindingFlags.Static ||| BindingFlags.Public)
149154 .FirstOrDefault ( fun m -> m.Name = " Contains" && m.GetParameters() .Length = 2 )
150155 with
151156 | 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 |])
164166
165167 let getField ( param : ParameterExpression ) fieldName = Expression.PropertyOrField ( param, fieldName)
166168
@@ -204,38 +206,38 @@ module ObjectListFilter =
204206 && memberType
205207 .GetInterfaces()
206208 .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))
207228 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
228231 | _ ->
229232 if `` member `` .Type = stringType then
230233 Expression.Call ( `` member `` , StringContainsMethod, Expression.Constant ( f.Value))
231234 else
232235 Expression.Call ( Expression.Convert ( `` member `` , stringType), StringContainsMethod, Expression.Constant ( f.Value))
233- | In f ->
236+ | In f when not ( f.Value.IsEmpty ) ->
234237 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 )
239241 | OfTypes types ->
240242 types
241243 |> Seq.map ( fun t -> buildTypeDiscriminatorCheck param t)
0 commit comments