如何在[<ReflectedDefinition>]标记的模块中获取函数的AST?

Bit*_*ler 5 f#

[<ReflectedDefinition>]
module Foo = 
    let x = 5
    let y () = 6
    let z a = a
Run Code Online (Sandbox Code Playgroud)

我试图找出如何在这种情况下获得AST的方法几次,并且一直失败。是时候在这里问问题了。

到目前为止,我认为模块将被映射到内部具有静态成员的类,因此,它应等效于:

[<ReflectedDefinition>] 
type Foo =
    static member x = 5
    static member y () = 6
    static member z a = a

let bar_members = 
    typeof<Bar>.GetMethods()
    |> Array.filter (fun mi -> match mi with | MethodWithReflectedDefinition x -> true | _ -> false)
    |> Array.map (fun m -> sprintf "%s: %A" (m.Name) (Expr.TryGetReflectedDefinition(m :> MethodBase) ) )
Run Code Online (Sandbox Code Playgroud)

在后一种情况下,我可以使用typeof<Foo>.GetMembers()(或GetMethods()?!),将其强制转换为,Reflection.MethodBase并用作的参数Expr.TryGetReflectedDefinition()

但不幸的是,这不适用于模块版本。

那么,该怎么做呢?

如果要使用代码,则可能要打开一些名称空间:

open Microsoft.FSharp.Quotations
open Microsoft.FSharp.Quotations.DerivedPatterns
open Microsoft.FSharp.Reflection
open System.Reflection
Run Code Online (Sandbox Code Playgroud)

The*_*ght 4

问题归结为实际获取模块的类型。为此,Phillip Trelford 提供了一个很好的答案: https: //stackoverflow.com/a/14706890/5438433

基本上,您向模块添加一个辅助值,该值返回该模块的类型:

[<ReflectedDefinition>]
module Foo = 
    type internal IMarker = interface end
    let fooType = typeof<IMarker>.DeclaringType

    let x = 5
    let y () = 6
    let z a = a
Run Code Online (Sandbox Code Playgroud)

然后您可以使用fooType来检索反映的定义。

 let foo_members = 
     Foo.fooType.GetMethods()
     |> Array.filter (fun mi -> match mi with | MethodWithReflectedDefinition x -> true | _ -> false)
     |> Array.map (fun m -> sprintf "%s: %A" (m.Name) (Expr.TryGetReflectedDefinition(m :> MethodBase) ) )
Run Code Online (Sandbox Code Playgroud)

然后我可以打印结果:

[|"get_fooType: Some PropertyGet (Some (Call (None, TypeOf, [])), DeclaringType, [])"; “get_x:一些值(5)”;"y: 一些 Lambda (unitVar0, Value (6))"; “z:一些 Lambda (a, a)”|]