[<ReflectedDefinition>]
module Foo =
let x = 5
let y () = 6
let z a = a
我试图找出如何在这种情况下多次获得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) ) )
在后一种情况下,我可以使用typeof<Foo>.GetMembers()
(或GetMethods()
?!),将其投放到Reflection.MethodBase
并将其用作Expr.TryGetReflectedDefinition()
的参数。
但不幸的是,这不适用于模块版本。
那么,怎么做呢?
如果您想使用代码,可能需要打开一些名称空间:
open Microsoft.FSharp.Quotations
open Microsoft.FSharp.Quotations.DerivedPatterns
open Microsoft.FSharp.Reflection
open System.Reflection
答案 0 :(得分:3)
问题来自于实际获取模块的类型。为了做到这一点,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
然后,您可以使用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) ) )
我可以,例如打印结果:
[|&#34; get_fooType:一些PropertyGet(Some(Call(None,TypeOf,[])),DeclaringType,[])&#34 ;; &#34; get_x:一些值(5)&#34 ;; &#34; y:一些Lambda(unitVar0,Value(6))&#34 ;; &#34; z:一些Lambda(a,a)&#34; |]
答案 1 :(得分:0)
对于用例,当反射的定义在另一个程序集中时(例如,像F#dll),您可以不使用标记接口技巧,如下所示:
open System
open Microsoft.FSharp.Quotations
open Microsoft.FSharp.Quotations.DerivedPatterns
open Microsoft.FSharp.Reflection
open System.Reflection
open FSharp.Reflection.FSharpReflectionExtensions
let tryGetReflectedModules (a : Assembly) : seq<TypeInfo> =
a.DefinedTypes
|> Seq.filter
(fun dt ->
dt.CustomAttributes
|> Seq.map (fun cad -> cad.AttributeType)
|> Seq.filter ((=) (typeof<ReflectedDefinitionAttribute>))
|> Seq.isEmpty
|> not
)
let astFromReflectedDefinition (mi : MethodInfo) : Expr option =
mi :> MethodBase |> Expr.TryGetReflectedDefinition
let reflectedMethodsOfAModule (m : System.Type) : (MethodInfo * Expr) [] =
m.GetMethods()
|> Array.map (fun m -> (m,astFromReflectedDefinition m))
|> Array.filter (snd >> Option.isSome)
|> Array.map (fun (x,y) -> (x, Option.get y))
let reflectAssembly (assemblyPath : string) =
let a = System.Reflection.Assembly.LoadFile(assemblyPath)
a
|> tryGetReflectedModules
|> Seq.map (fun x -> (x,reflectedMethodsOfAModule (x.AsType())))
例如,我用于测试上面代码的程序集如下所示:
namespace Input
[<ReflectedDefinition>]
module Api =
let trace s =
for _ in [0..3] do System.Diagnostics.Trace.WriteLine s
[<ReflectedDefinition>]
module Foo =
let foobar (x : string) : string =
x.ToUpper()
您可以获得程序集中的顶级类型,这恰好是(静态)类,表示Fsharp程序集的模块并测试ReflectedDefinitionAttribute
存在。然后,你从那里拿走它。