为了完成 Marcelo 的回答,是的,您可以为此任务使用引号:
open Microsoft.FSharp.Quotations
open Microsoft.FSharp.Quotations.Patterns
let velocity = 5
let fn (e:Expr) =
match e with
| PropertyGet (e, pi, li) -> pi.Name
| _ -> failwith "not a let-bound value"
let name = fn <@velocity@>
printfn "%s" name
正如您在代码中看到的那样,F# let-bound 顶级定义值(函数或变量)被实现为类的属性。
我再也找不到显示如何使用 C# 以功能方式重写一段 F# 代码的链接。PropertyGet
看到代码,你为什么需要一个模式就很明显了。
现在,如果您也想评估表达式,则需要在项目中安装F# powerpack和引用FSharp.PowerPack.Linq
。
它EvalUntyped
在类上添加了一个方法Expr
..
open Microsoft.FSharp.Linq.QuotationEvaluation
let velocity = 5
let fn (e:Expr) =
match e with
| PropertyGet (eo, pi, li) -> pi.Name, e.EvalUntyped
| _ -> failwith "not a let-bound value"
let name, value = fn <@velocity@>
printfn "%s %A" name value
如果您需要为实例的方法执行此操作,我将这样做:
let velocity = 5
type Foo () =
member this.Bar (x:int) (y:single) = x * x + int y
let extractCallExprBody expr =
let rec aux (l, uexpr) =
match uexpr with
| Lambda (var, body) -> aux (var::l, body)
| _ -> uexpr
aux ([], expr)
let rec fn (e:Expr) =
match e with
| PropertyGet (e, pi, li) -> pi.Name
| Call (e, mi, li) -> mi.Name
| x -> extractCallExprBody x |> fn
| _ -> failwith "not a valid pattern"
let name = fn <@velocity@>
printfn "%s" name
let foo = new Foo()
let methodName = fn <@foo.Bar@>
printfn "%s" methodName
只是回到显示用法的代码片段,如果您想要/需要保持类型安全EvalUntyped
,您可以添加显式类型参数 forExpr
和向下转换 ( )::?>
let fn (e:Expr<'T>) =
match e with
| PropertyGet (eo, pi, li) -> pi.Name, (e.EvalUntyped() :?> 'T)
| _ -> failwith "not a let-bound value"
let name, value = fn <@velocity@> //value has type int here
printfn "%s %d" name value