Не удалось найти выражение PropertyGet в цитате F # - PullRequest
0 голосов
/ 26 апреля 2020

Моя цель - создать функцию, которая принимает обобщенную функцию c property accesser и возвращает имя свойства, к которому она обращается. Например:

type Person = { Name: string; Age: int }
let blake = { Name = "Blake"; Age = 30 }

let requestedProperty = propertyAccess (fun p -> p.Name) // should return "Name"

Я хочу, чтобы propertyAccess было generi c и могло использоваться с любым типом. Он может иметь подпись:

'T -> 'TProperty -> string

До сих пор я пытался создать цитату из функции делегата и шаблона, соответствующего дереву выражений, в поисках PropertyGet. К сожалению, дерево выражения цитаты имеет форму:

NewDelegate (Func`2, delegateArg0,
             Application (ValueWithName (<fun:result@88>, f), delegateArg0))

, и я не могу найти PropertyGet. Как мне этого добиться?

Весь код выглядит так:


let propertyAccess (f: 'T -> 'TProperty) =
    let expression = <@ f @>

    let rec findProperty expr =
        match expr with
        | Application(ex1, ex2) -> findProperty ex1
        | PropertyGet(o, info, lst) -> sprintf "Property: %s" info.Name 
        | Lambda(param, body) -> findProperty body
        | NewDelegate(t, lst, ex) -> findProperty ex
        | ValueWithName(ob, t, s) -> sprintf "ValueName: %s" s
        | _ -> "Couldn't find property"

type Person = { Name: string; Age: int }
let blake = { Name = "Blake"; Age = 30 }

let requestedProperty = propertyAccess (fun p -> p.Name) // should return "Name"

Спасибо

1 Ответ

0 голосов
/ 26 апреля 2020

Проблема в том, что вы просто заключаете значение (функции) в кавычку, и AST в конечном итоге становится просто ValueWithName.

Вы хотите, чтобы компилятор автоматически указывал выражение вашего аргумента.

type Props =
    static member propertyAccess ([<ReflectedDefinition>] expr: Expr<'a -> 'b>) =
      match expr with
      | Patterns.Lambda(_, Patterns.PropertyGet(_, prop, _)) -> prop.Name
      | _ -> failwith "Invalid property"

Обратите внимание, что это будет работать только на элементе stati c, а не на vals.

let requestedProperty = Props.propertyAccess (fun p -> p.Name) // returns "Name"

Вы также можете рассмотреть Expression<Func<T, TValue>>, который работает почти так же.

...