Reputation: 80
I want to match the object obj1 of type "obj" according to its actual type. The problem is that the type check pattern for list type (the second one in the example below) does not match F# lists.
let obj1 = [1;2;3] :> obj
match obj1 with
| :? System.Array as a -> printfn "it's an array: %A" a
| :? List<_> as l -> printfn "It's a list: %A" l
| _ -> printfn "other type"
Outputs "other type", while I expect it to be "It's a list: [1;2;3]"
How to check for list type properly?
Upvotes: 4
Views: 1686
Reputation: 233150
Daniel Fabian has already explained the problem in his answer.
One way to implement his solution is with an Active Pattern:
let (|IsList|_|) (candidate : obj) =
let t = candidate.GetType()
if t.IsGenericType && t.GetGenericTypeDefinition() = typedefof<list<_>>
then Some (candidate :?> System.Collections.IEnumerable)
else None
You can now change the match to use this active pattern:
let obj1 = [1;2;3] :> obj
match obj1 with
| :? System.Array as a -> printfn "it's an array: %A" a
| IsList l -> printfn "It's a list: %A" l
| _ -> printfn "other type"
This prints:
> It's a list: [1; 2; 3]
Upvotes: 4
Reputation: 3838
obj : [any type]
What you need to do, is distinguish if your obj is a generic type. Get the type of it by means of .GetType()
there you'll find the appropriate property.
obj : [some type of the form T<'T1, 'T2, ..., 'Tn> for concrete types T1, T2, ..., Tn]
If it is, then you get the generic type definition by using the appropritate method on the type you got by means of .GetType()
obj : [some type of the form T<'T1, 'T2, ..., 'Tn> with T1, T2, ..., Tn not bound yet]
and this type you now can compare to typedefof<_ list>
(_ list
is inferred to be obj list
, but typedefof
as opposed to typeof
does the getting of generic type definition for you already).
The final code looks something like this (pseudo-code)
let ty = obj.GetType()
match obj with
| unknownType when not ty.IsGenericType -> "some non-generic type, probably a concrete collection"
| list when ty.GetGenericTypeDefinition() = typedefof<_ list> -> "list"
| array when ty.GetGenericTypeDefinition() = typedefof<_ array> -> "array"
| _ -> "something else, i.e. a generic type that we don't know"
Upvotes: 3
Reputation: 544
I would not call List<_> as F# list - it is .NET framework type. You can match it with (int list) type - it is F# list:
match obj1 with | :? (int list) as l -> 1 | _ -> 0
Upvotes: -2