5 people like it.

Dynamic Invocation of Generic Functions In A Module

A quick snippet showing three different ways of dynamically/reflectively locating a module then invoking a generic function. The first two don't rely on a class. But the third is more readable/understandable for most .NET devs.

 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: 
open Microsoft.FSharp.Quotations.Patterns

module Test =
    // https://stackoverflow.com/a/26621814
    // relies on at least surface-level knowledge of how F# quotations work
    let rec private moduleType = <@ moduleType @> |> function PropertyGet (_, info, _) -> info.DeclaringType
    let ModuleTypeQt = moduleType

    // https://stackoverflow.com/a/14706890
    // relies on the fact that Modules are actually implemented as static classes
    type private IAssemblyLocator = interface end
    let ModuleTypeTo = typeof<IAssemblyLocator>.DeclaringType

    let sayHi<'a> () =
        printfn "Hello %A" (typeof<'a>.Name)

// not a module, but is perhaps the most understandable to most devs coming in
[<AbstractClass; Sealed>]
type Test private () =
    static member sayHi<'a> () =
        printfn "Hello %A" (typeof<'a>.Name)

Test.ModuleTypeQt.GetMethod(nameof Test.sayHi).MakeGenericMethod(typeof<unit>).Invoke(null, [| |])
Test.ModuleTypeTo.GetMethod(nameof Test.sayHi).MakeGenericMethod(typeof<unit>).Invoke(null, [| |])
typeof<Test>.GetMethod(nameof Test.sayHi).MakeGenericMethod(typeof<unit>).Invoke(null, [| |])
namespace Microsoft
namespace Microsoft.FSharp
namespace Microsoft.FSharp.Quotations
module Patterns

from Microsoft.FSharp.Quotations
val private moduleType : System.Type
active recognizer PropertyGet: Quotations.Expr -> (Quotations.Expr option * System.Reflection.PropertyInfo * Quotations.Expr list) option
val info : System.Reflection.PropertyInfo
property System.Reflection.MemberInfo.DeclaringType: System.Type with get
val ModuleTypeQt : System.Type
type private IAssemblyLocator
val ModuleTypeTo : System.Type
val typeof<'T> : System.Type
val sayHi<'a> : unit -> unit
val printfn : format:Printf.TextWriterFormat<'T> -> 'T
Multiple items
type AbstractClassAttribute =
  inherit Attribute
  new : unit -> AbstractClassAttribute

--------------------
new : unit -> AbstractClassAttribute
Multiple items
type SealedAttribute =
  inherit Attribute
  new : unit -> SealedAttribute
  new : value:bool -> SealedAttribute
  member Value : bool

--------------------
new : unit -> SealedAttribute
new : value:bool -> SealedAttribute
Multiple items
module Test

from Script

--------------------
type Test =
  private new : unit -> Test
  static member sayHi : unit -> unit

--------------------
private new : unit -> Test
val nameof : 'T -> string
Multiple items
val sayHi<'a> : unit -> unit

--------------------
static member Test.sayHi : unit -> unit
type unit = Unit
Raw view Test code New version

More information

Link:http://fssnip.net/7ZQ
Posted:4 years ago
Author:Cerberus (FSharp Discord)
Tags: dynamic programming , generic functions , generic programming , generics , invoke , quotations , reflection , static generics