I believe what you are looking for is Microsoft.FSharp.Reflection.GetInfo:

#lightopen System
open Microsoft.FSharp.Reflection
open Microsoft.FSharp.Reflection.Type

type DUClass =
| A
| B of int * string
| C of string * int list
| D of DUClass array

let PrintSumTypeConstructors (duType:Type) =

match GetInfo duType with
| SumType tl ->
printfn "%s" duType.Name
tl |> List.iter (fun (name, tyl) ->
printfn "\t%s of %s" name (tyl |> List.map (fun (s,t) -> t.ToString ()) |> String.concat " * ")
)
| _ -> failwith "No discriminated union type"

(*
[Output]
DUClass
A of
B of System.Int32 * System.String
C of System.String * Microsoft.FSharp.Collections.List`1[System.Int32]
D of Adhoc+DUClass[]
*)

PrintSumTypeConstructors (typeof<DUClass>)
Console.ReadKey(true)

By on 3/28/2008 11:02 AM ()

to clarify: I have used GetInfo to learn about the type. Now I need to get at the actual values contained by a specific object. Searching through Tomas P's FSharp.WebTools, I have found, in web_serializer.fs, a use of Microsoft.FSharp.Reflection.Value. GetSumRecordReader which I am hoping will do what I want. ~TMSteve

By on 3/28/2008 11:15 AM ()

My mistake. You are correct, GetSumRecordReader is what you want:

open Microsoft.FSharp.Reflection.Value

let GetSumTypeValues (duInstance:obj) =
// Get the tag index for the given duInstance
let objToTagIndex = GetSumTagReader (duInstance.GetType())
let tagIndex = objToTagIndex duInstance

// GetSumRecordReader takes a Type * int and returns obj -> obj[].
// That is the type of a discriminated union and the integer 'tag' index
// and returns a function that given an instance of that tag, returns its values
let duInstanceRecordReader = GetSumRecordReader (duInstance.GetType(), tagIndex)
let duInstanceValues = duInstanceRecordReader duInstance

printfn "Instance's values = %A" duInstanceValues

let x = B(1024, "Kilobyte")
GetSumTypeValues (x :> obj)

(*
[Outputs]
Instance's values = [|1024; "Kilobyte"|]
*)

By on 3/28/2008 11:17 AM ()

Thanks Chris. That's exactly what I needed to see for code! Here is my complete example after incorporating your code snippet:

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#light

module FR = Microsoft.FSharp.Reflection
module FV = Microsoft.FSharp.Reflection.Value

/// Given a discriminated union instance, return (name, values, baseName)
let pullChoiceRecord (du:obj) : string * obj[] * string =
  let dut = du.GetType();
  let info = FR.Type.GetInfo(dut)

  // Get the tag index for the given du instance
  let objToTagIndex = FV.GetSumTagReader dut
  let tagIndex = objToTagIndex du

  // GetSumRecordReader takes (Type * int)
  // (type of a discriminated union, an integer 'tag' index of that du)
  // and returns a function (obj -> obj[])
  // that given an instance of that tag, returns its values.
  let duRecordReader = FV.GetSumRecordReader (dut, tagIndex)
  let duValues = duRecordReader du
  let baseName = dut.BaseType.Name
  let name =
    match info with
      | FR.SumType sum ->
        let (name, _) = List.nth sum tagIndex
        name
      | _ -> failwith "pullChoiceRecord- expected SumType"
  
  (name, duValues, baseName)

/// du = a discriminated union
let findData2 (duInstance) =
  let (name, values, baseName) = pullChoiceRecord (duInstance :> obj)
  printfn "[%s] %s = %A" baseName name values

// ---------- Tests ----------
type T =
  | A of int
  | B of int * string

let t2 = B (34, "ab")

let findData1 (t:T) =
  match t with
  | A i -> printfn "found A=%A" i
  | B (i, s) -> printfn "found B=(%A, %A)" i s

findData1 t2  // Direct knowledge of type.
findData2 t2  // Reflection

// ===== output =====>
//found B=(34, "ab")
//[T] B = [|34; "ab"|]
By on 3/28/2008 12:29 PM ()
IntelliFactory Offices Copyright (c) 2011-2012 IntelliFactory. All rights reserved.
Home | Products | Consulting | Trainings | Blogs | Jobs | Contact Us | Terms of Use | Privacy Policy | Cookie Policy
Built with WebSharper