Получение атрибутов из аргумента функции - PullRequest
1 голос
/ 04 мая 2011

Если у меня есть функция, которая принимает другую функцию:

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

Как получить доступ к пользовательским атрибутам g из f?

Я думаю, что мне здесь не хватает чего-то действительно очевидного.

Ответы [ 2 ]

5 голосов
/ 04 мая 2011

В общем случае это невозможно, поскольку при использовании функции в качестве аргумента (например, 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 @>
0 голосов
/ 04 мая 2011
let f (g:unit->unit) =
    printfn "%d" (g.GetType().GetCustomAttributes(true).Count())
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...