ddl
ddl

Reputation: 329

F# how to list functions with custom attribute?

I'm trying to create some kind of interface, but i cannot find how to use custom attributes in F# as MSDN only shows usage of CLR attributes. This is what i want to achieve:

open System

type Command (name : string) =
    inherit Attribute()    
    member this.Name = name

[<Command("something")>]
let doSomething () = 
    Console.Write("I'm doing something") 

[<Command("somethingElse")>]
let doSomethingElse () =
    Console.Write("I'm doing something else") 

[<EntryPoint>]
let main args =
    let command = Console.ReadLine()
    // find function where Command.Name = command and call it
    Console.Read()
    0

Upvotes: 2

Views: 937

Answers (2)

scrwtp
scrwtp

Reputation: 13577

To extend on your answer, a more generic approach would be to get all the types and then filter the functions that have the attribute you're looking for (as your approach would break down once your application grows and no longer has everything "packed" into the Program class):

let getCommands () =
    let types = Assembly.GetExecutingAssembly().GetTypes()
    let commands = 
        types 
        |> Array.collect (fun typ -> typ.GetMethods())
        |> Array.choose (fun mi -> 
            mi.CustomAttributes 
            |> Seq.tryFind (fun attr -> attr.AttributeType = typeof<Command>)
            |> Option.map (fun attr -> attr, mi))

    let commandsMap = 
        commands
        |> Seq.map (fun (attr, mi) -> 
            let name =
                let arg = attr.ConstructorArguments.[0]
                unbox<string> arg.Value
            name, mi)
        |> Map.ofSeq

    commandsMap

This gets all the functions from all the types in the executing assembly, then filters out everything that doesn't have command attribute. Then it builds a map where the key is the attribute argument and the value is the MethodInfo of the function.

Upvotes: 4

ddl
ddl

Reputation: 329

Ok, found it.

Reflection.Assembly.GetExecutingAssembly().GetType("Program").GetMethods()

Program typename is not viable in code so it cannot be used in typeof<Program>, but this type exists and can be taken from assembly.

Upvotes: 0

Related Questions