29 people like it.

Convert a obj list to a typed list without generics

This is used for building things with reflection at runtime. As ConstructorInfo arguments require typed collections, it is necessary when parsing to reflected records to first build up contents and then afterward convert the collected obj[] to a 'a[]. This is finally cast back to obj so it can be used as a ConstructorInfo argument.

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
21: 
22: 
23: 
24: 
25: 
26: 
27: 
28: 
29: 
type ReflectiveListBuilder = 
    static member BuildList<'a> (args: obj list) = 
        [ for a in args do yield a :?> 'a ] 
    static member BuildTypedList lType (args: obj list) = 
        typeof<ReflectiveListBuilder>
            .GetMethod("BuildList")
            .MakeGenericMethod([|lType|])
            .Invoke(null, [|args|])

//Also, here's a caching version because reflection is slow.  System.Type doesn't
//support the comparison constraint so I just use the the full name of the type.

type CachingReflectiveListBuilder = 
    static member ReturnTypedListBuilder<'a> () : obj list -> obj = 
        let createList (args : obj list) = [ for a in args do yield a :?> 'a ] :> obj
        createList
    static member private builderMap = ref Map.empty<string, obj list -> obj>
    static member BuildTypedList (lType: System.Type) =
        let currentMap = !CachingReflectiveListBuilder.builderMap
        if Map.containsKey (lType.FullName) currentMap then
            currentMap.[lType.FullName]
        else
           let builder = typeof<CachingReflectiveListBuilder>
                            .GetMethod("ReturnTypedListBuilder")
                            .MakeGenericMethod([|lType|])
                            .Invoke(null, null) 
                            :?> obj list -> obj
           CachingReflectiveListBuilder.builderMap := Map.add lType.FullName builder currentMap
           builder  
static member ReflectiveListBuilder.BuildList : args:obj list -> 'a list

Full name: Script.ReflectiveListBuilder.BuildList
val args : obj list
type obj = System.Object

Full name: Microsoft.FSharp.Core.obj
type 'T list = List<'T>

Full name: Microsoft.FSharp.Collections.list<_>
val a : obj
static member ReflectiveListBuilder.BuildTypedList : lType:System.Type -> args:obj list -> obj

Full name: Script.ReflectiveListBuilder.BuildTypedList
val lType : System.Type
val typeof<'T> : System.Type

Full name: Microsoft.FSharp.Core.Operators.typeof
type ReflectiveListBuilder =
  static member BuildList : args:obj list -> 'a list
  static member BuildTypedList : lType:Type -> args:obj list -> obj

Full name: Script.ReflectiveListBuilder
type CachingReflectiveListBuilder =
  static member BuildTypedList : lType:Type -> (obj list -> obj)
  static member ReturnTypedListBuilder : unit -> (obj list -> obj)
  static member private builderMap : Map<string,(obj list -> obj)> ref

Full name: Script.CachingReflectiveListBuilder
static member CachingReflectiveListBuilder.ReturnTypedListBuilder : unit -> (obj list -> obj)

Full name: Script.CachingReflectiveListBuilder.ReturnTypedListBuilder
val createList : (obj list -> obj)
static member private CachingReflectiveListBuilder.builderMap : Map<string,(obj list -> obj)> ref

Full name: Script.CachingReflectiveListBuilder.builderMap
Multiple items
val ref : value:'T -> 'T ref

Full name: Microsoft.FSharp.Core.Operators.ref

--------------------
type 'T ref = Ref<'T>

Full name: Microsoft.FSharp.Core.ref<_>
Multiple items
module Map

from Microsoft.FSharp.Collections

--------------------
type Map<'Key,'Value (requires comparison)> =
  interface IEnumerable
  interface IComparable
  interface IEnumerable<KeyValuePair<'Key,'Value>>
  interface ICollection<KeyValuePair<'Key,'Value>>
  interface IDictionary<'Key,'Value>
  new : elements:seq<'Key * 'Value> -> Map<'Key,'Value>
  member Add : key:'Key * value:'Value -> Map<'Key,'Value>
  member ContainsKey : key:'Key -> bool
  override Equals : obj -> bool
  member Remove : key:'Key -> Map<'Key,'Value>
  ...

Full name: Microsoft.FSharp.Collections.Map<_,_>

--------------------
new : elements:seq<'Key * 'Value> -> Map<'Key,'Value>
val empty<'Key,'T (requires comparison)> : Map<'Key,'T> (requires comparison)

Full name: Microsoft.FSharp.Collections.Map.empty
Multiple items
val string : value:'T -> string

Full name: Microsoft.FSharp.Core.Operators.string

--------------------
type string = System.String

Full name: Microsoft.FSharp.Core.string
static member CachingReflectiveListBuilder.BuildTypedList : lType:System.Type -> (obj list -> obj)

Full name: Script.CachingReflectiveListBuilder.BuildTypedList
namespace System
type Type =
  inherit MemberInfo
  member Assembly : Assembly
  member AssemblyQualifiedName : string
  member Attributes : TypeAttributes
  member BaseType : Type
  member ContainsGenericParameters : bool
  member DeclaringMethod : MethodBase
  member DeclaringType : Type
  member Equals : o:obj -> bool + 1 overload
  member FindInterfaces : filter:TypeFilter * filterCriteria:obj -> Type[]
  member FindMembers : memberType:MemberTypes * bindingAttr:BindingFlags * filter:MemberFilter * filterCriteria:obj -> MemberInfo[]
  ...

Full name: System.Type
val currentMap : Map<string,(obj list -> obj)>
property CachingReflectiveListBuilder.builderMap: Map<string,(obj list -> obj)> ref
val containsKey : key:'Key -> table:Map<'Key,'T> -> bool (requires comparison)

Full name: Microsoft.FSharp.Collections.Map.containsKey
property System.Type.FullName: string
val builder : (obj list -> obj)
val add : key:'Key -> value:'T -> table:Map<'Key,'T> -> Map<'Key,'T> (requires comparison)

Full name: Microsoft.FSharp.Collections.Map.add

More information

Link:http://fssnip.net/1L
Posted:13 years ago
Author:Rick Minerich
Tags: reflection , collections