In the following snippet my intention is to convert a System.Object (which could be an FSharpList) to a list of whatever generic type it is holding.
match o with
| :? list<_> -> addChildList(o :?> list<_>)
| _ -> addChild(o)
Unfortunately only list<obj>
is ever matched as a list. I would like list<Foo>
to also be matched as a list.
For some context, I am trying to traverse an object structure by reflection in order to build a TreeView of the class and its children. Consider the following class:
type Entity = {
Transform : Matrix
Components : obj list
Children : Entity list
}
I would like to build a tree that shows me all the classes that is contained in the entity. Through reflection, I can obtain all the properties of an object and also their values (The value is important, since I want to display the different elements in a list with the Name property of the element if it has one):
let o = propertyInfo.GetValue(obj, null)
This value could be a list of some type, but the value return is just a System.Object I run into problems when trying to convert this object to a list. I am forced to do the following:
match o with
| :? list<obj> -> addChildList(o :?> list<obj>)
| :? list<Entity> -> addChildList(o :?> list<Entity>)
| _ -> addChild(o)
Here I have to specify exactly the type that I am trying to convert to.
I would really like to write this:
match o with
| :? list<_> -> addChildList(o :?> list<_>)
| _ -> addChild(o)
Unfortunately this only ever matches on list< obj >
It turns out that either
list<'a>
orarray<'a>
can be matched asseq<obj>
I don't really care that it is a list. As long as I can iterate over it.
Unfortunately, there's no easy way to do what you want. Type tests can only be used with specific types, and even if the type test passed, the conversion operator
:?>
also only works to cast expressions to specific types so the right hand side of your match wouldn't do what you want anyway. You can partially work around this issue using an active pattern:This active pattern can be used as follows:
where you've created a variation of
addChildList
which takes a typet
and an objecto
(with runtime typelist<t>
) instead of taking a generic list.This is a bit clunky, but I can't think of a cleaner solution.