从函数参数中检索属性

Rei*_*aka 1 reflection f# attributes

如果我有一个函数接受另一个函数:

[<SomeAttribute()>]
let f (g:unit->unit) =
    //Want to get g's custom attributes
Run Code Online (Sandbox Code Playgroud)

如何从f访问g的自定义属性?

我想我错过了一些非常明显的东西.

Tom*_*cek 5

这通常不可能,因为当您使用函数作为参数(例如f foo)时,F#编译器将foo值包装到某个对象中.foo从这个对象中提取实际的方法引用将非常困难(并且只有在编译器没有进行一些优化时才会起作用).

但是,您可以使用F#引用获得所需的行为.unit -> unitf可以采用引用函数代替函数Expr<unit -> unit>.然后你可以使用f <@ foo @>函数调用函数,函数可以提取方法参考并调用foo.

这是一个例子.它需要引用F#PowerPack(以便它可以评估报价).在这个简单的案例中,评估应该非常有效:

#r @"FSharp.PowerPack.Linq.dll"

type SomeAttribute(name:string) =
  inherit System.Attribute()
  member x.Name = name

// Example function with some attribute
[<SomeAttribute("Test")>]
let g () = printfn "Hello"

open Microsoft.FSharp.Quotations
open Microsoft.FSharp.Linq.QuotationEvaluation

// Takes a quotation instead of a function value
let f (g:Expr<unit->unit>) =
  // Extract method info & attributes from the quotation
  match g with
  | DerivedPatterns.Lambdas(_, Patterns.Call(_, mi, _)) ->
      let attrs = mi.GetCustomAttributes(typeof<SomeAttribute>, false)
      for a in attrs |> Seq.cast<SomeAttribute> do
        printfn "%A" a.Name
  | _ -> 
      failwith "Argument must be of the form <@ foo @>!"

  // Compile the function so that it can be executed (the compilation
  // takes some time, but calling invoke should be fast)
  let invoke = g.Compile()()
  invoke()
  invoke()

// And this is how you call the function
f <@ g @>
Run Code Online (Sandbox Code Playgroud)