3 people like it.

Walking object graphs

Implemetation picked up from http://msdn.microsoft.com/en-us/library/system.runtime.serialization.objectmanager.aspx

 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: 
open System
open System.Reflection
open System.Runtime.Serialization

let gatherObjs (o : obj) =
    let gen = new ObjectIDGenerator()

    let rec traverse (gathered : obj list) : obj list -> obj list =
        function
        | [] -> gathered
        | o :: rest when o = null -> traverse gathered rest
        | o :: rest ->
            let firstTime = ref false
            gen.GetId(o, firstTime) |> ignore
            if firstTime.Value then
                let t = o.GetType()
                let nested =
                    if t.IsValueType then []
                    elif t.IsArray then
                        [ for e in (o :?> Array) -> e ]
                    else
                        let fields = t.GetFields(BindingFlags.Instance ||| BindingFlags.Public ||| BindingFlags.NonPublic)
                        [ for fInfo in fields -> fInfo.GetValue o ]

                traverse (o :: gathered) (nested @ rest)

            else traverse gathered rest

    traverse [] [o]


let gatherTypes : obj -> _ =
    gatherObjs
    >> Seq.map (fun o -> o.GetType())
    >> Seq.distinctBy (fun t -> t.AssemblyQualifiedName)
    >> Seq.toList
namespace System
namespace System.Reflection
namespace System.Runtime
namespace System.Runtime.Serialization
val gatherObjs : o:obj -> obj list

Full name: Script.gatherObjs
val o : obj
type obj = Object

Full name: Microsoft.FSharp.Core.obj
val gen : ObjectIDGenerator
Multiple items
type ObjectIDGenerator =
  new : unit -> ObjectIDGenerator
  member GetId : obj:obj * firstTime:bool -> int64
  member HasId : obj:obj * firstTime:bool -> int64

Full name: System.Runtime.Serialization.ObjectIDGenerator

--------------------
ObjectIDGenerator() : unit
val traverse : (obj list -> obj list -> obj list)
val gathered : obj list
type 'T list = List<'T>

Full name: Microsoft.FSharp.Collections.list<_>
val rest : obj list
val firstTime : bool ref
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<_>
ObjectIDGenerator.GetId(obj: obj, firstTime: byref<bool>) : int64
val ignore : value:'T -> unit

Full name: Microsoft.FSharp.Core.Operators.ignore
property Ref.Value: bool
val t : Type
Object.GetType() : Type
val nested : obj list
property Type.IsValueType: bool
property Type.IsArray: bool
val e : obj
type Array =
  member Clone : unit -> obj
  member CopyTo : array:Array * index:int -> unit + 1 overload
  member GetEnumerator : unit -> IEnumerator
  member GetLength : dimension:int -> int
  member GetLongLength : dimension:int -> int64
  member GetLowerBound : dimension:int -> int
  member GetUpperBound : dimension:int -> int
  member GetValue : [<ParamArray>] indices:int[] -> obj + 7 overloads
  member Initialize : unit -> unit
  member IsFixedSize : bool
  ...

Full name: System.Array
val fields : FieldInfo []
Type.GetFields() : FieldInfo []
Type.GetFields(bindingAttr: BindingFlags) : FieldInfo []
type BindingFlags =
  | Default = 0
  | IgnoreCase = 1
  | DeclaredOnly = 2
  | Instance = 4
  | Static = 8
  | Public = 16
  | NonPublic = 32
  | FlattenHierarchy = 64
  | InvokeMethod = 256
  | CreateInstance = 512
  ...

Full name: System.Reflection.BindingFlags
field BindingFlags.Instance = 4
field BindingFlags.Public = 16
field BindingFlags.NonPublic = 32
val fInfo : FieldInfo
FieldInfo.GetValue(obj: obj) : obj
val gatherTypes : (obj -> Type list)

Full name: Script.gatherTypes
module Seq

from Microsoft.FSharp.Collections
val map : mapping:('T -> 'U) -> source:seq<'T> -> seq<'U>

Full name: Microsoft.FSharp.Collections.Seq.map
val distinctBy : projection:('T -> 'Key) -> source:seq<'T> -> seq<'T> (requires equality)

Full name: Microsoft.FSharp.Collections.Seq.distinctBy
property Type.AssemblyQualifiedName: string
val toList : source:seq<'T> -> 'T list

Full name: Microsoft.FSharp.Collections.Seq.toList
Raw view Test code New version

More information

Link:http://fssnip.net/gM
Posted:11 years ago
Author:Eirik Tsarpalis
Tags: reflection , object graph