FSharp type that corresponds to the list type

I want to match the object obj1 of type "obj" according to its actual type. The problem is that the type checking pattern for the list type (the second in the example below) doesn't match F # lists.

let obj1 = [1;2;3] :> obj
match obj1 with
    | :? System.Array as a -> printfn "it an array: %A" a
    | :? List<_> as l -> printfn "It a list: %A" l
    | _ -> printfn "other type"

      

Outputs "another type" while I expect it to be "This is a list: [1; 2; 3]"

How to check the list type correctly?

+3


source to share


3 answers


Daniel Fabian has already explained the problem in his answer.

One way to implement your solution is Active Template :

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 template:



let obj1 = [1;2;3] :> obj
match obj1 with
    | :? System.Array as a -> printfn "it an array: %A" a
    | IsList l -> printfn "It a list: %A" l
    | _ -> printfn "other type"

      

Prints:

> It a list: [1; 2; 3]

      

+1


source


obj : [any type]

      

What you need to do is differentiate if your obj is a generic type. Get its type using .GetType()

there you will find the corresponding property.

obj : [some type of the form T<'T1, 'T2, ..., 'Tn> for concrete types T1, T2, ..., Tn]

      

If so, you get a generic type definition with the type assignment method you got with .GetType()



obj : [some type of the form T<'T1, 'T2, ..., 'Tn> with T1, T2, ..., Tn not bound yet]

      

and this type can now be compared with typedefof<_ list>

( _ list

defined as obj list

, but typedefof

unlike typeof

already gets a generic type definition for you).

The last code looks something like this (pseudocode)

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"

      

+3


source


I wouldn't call List <_> as F # list - it's a .NET framework type. You can map it to type (int list) - this is an F # list:

match obj1 with | :? (int list) as l -> 1 | _ -> 0

      

-2


source







All Articles