В общем случае это невозможно, поскольку при использовании функции в качестве аргумента (например, f foo
) компилятор F # оборачивает значение foo
в некоторый объект.Извлечь фактическую ссылку на метод foo
из этого объекта было бы очень сложно (и это работало бы, только если компилятор не выполнил некоторые оптимизации).
Однако вы можете получить желаемое поведение, используя цитаты F #.Вместо функции unit -> unit
ваш f
может использовать функцию в кавычках 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 @>