8

I have module like this

module CommonModule

    let addFive x =
        x+5

    let multiFive x =
        x*5

And I would like to list methods of this module by reflection. I found this: Can you list the contents of a namespace or module in F#, but I don't know how to use it. I'm new in F#. Please help

lukaszb
  • 159
  • 13
  • 1
    Where are you trying to make the list? In another app? Most documentation you will find on reflection will probably be in c#. Note that an f# module correlates to a static class at the assembly level. So you would need to load the assembly, find the type with your modules name, and then iterate that types methods – JamesFaix Jun 12 '18 at 12:48

1 Answers1

8

I think the only way to do this is to declare a type inside the module, then use reflection to get the DeclaringType and call GetMethods on that:

open System.Reflection

module CommonModule =
    type Marker = interface end

    let f x = x * x

typeof<CommonModule.Marker>.DeclaringType.GetMethods()

This will give you a MethodInfo [] containing f and the methods inherited from System.Object:

[|Int32 f(Int32); System.String ToString(); Boolean Equals(System.Object);
Int32 GetHashCode(); System.Type GetType()|]

EDIT (responding to lukaszb's comment)

If you want to look up the module by name, you'll need to get the assembly first, then find the module type within the assembly and call GetMethods. To do this for the previous example, you would add the following code:

// Get the assembly somehow (by name, by GetEntryAssembly, etc)
let assembly = Assembly.GetExecutingAssembly()

// Retrieve the methods (including F# functions) on the module type
let functions =
    match assembly.GetTypes() |> Array.tryFind (fun t -> t.Name = "CommonModule") with
    | Some moduleType -> moduleType.GetMethods()
    | None -> [||]

// Find the function you want
match functions |> Array.tryFind (fun f -> f.Name = "f") with
| Some f -> f.Invoke(null, [|2|]) // Invoke the function
| None -> failwith "Function `f` not found"

One benefit of doing it this way is that you no longer need the Marker type in the module.

Aaron M. Eshbach
  • 6,380
  • 12
  • 22