【发布时间】:2014-02-26 12:21:51
【问题描述】:
需要追踪。装饰器应该打印函数名、参数值和返回值。与其每次都为每个函数编写一个装饰器,不如以编程方式实现这一点。
【问题讨论】:
-
查看 AOP 解决方案,例如PostSharp。
标签: f# wrapper decorator trace
需要追踪。装饰器应该打印函数名、参数值和返回值。与其每次都为每个函数编写一个装饰器,不如以编程方式实现这一点。
【问题讨论】:
标签: f# wrapper decorator trace
可以通过MethodBase.GetCurrentMethod 使用反射发现当前函数名称。函数可以很容易地用内联函数进行修饰:
let inline log args f =
let mi = System.Reflection.MethodBase.GetCurrentMethod()
let result = f ()
printf "%s %A -> %A" mi.Name args result
let add a b = log (a,b) (fun () -> a + b)
add 1 1
哪个打印:add (1, 1) -> 2
编辑:另一种选择是创建一个包装函数,即:
let inline wrap f =
fun ps ->
let result = f args
printfn "%A -> %A" args result
result
let add (a,b) = a + b
wrap add (1,1)
但是在这种情况下,没有一种简单的方法可以以编程方式检索函数名称。
另一种选择可能是开发一个类型提供程序,它将程序集路径作为参数并提供所有成员的包装版本。
【讨论】:
[<MethodImpl(MethodImplOptions.NoInlining)>] 放在包含对 log 的调用的方法上(否则它可能被内联到自己的调用者中,从而导致误导性跟踪) .
let (!) = wrap
我之前也有同样的愿望,发现目前没有针对 F# 的自动化解决方案。
见:Converting OCaml to F#: Is there a simple way to simulate OCaml top-level #trace in F#
虽然 OCaml 的时间旅行跟踪功能是与所需进行比较的最有用的调试功能,但它并不完全适合;但是当我使用 OCaml 时,它是我使用的第一个检查工具。
见:Using PostSharp with F# - Need documentation with working example
另外,使用AOP(即PostSharp)的建议也是另一个不错的建议,正如Gael Fraiteur 的回复,PostSharp 的首席工程师指出:
PostSharp 不正式支持 F#。
除了使用 Phillip Trelford 建议的反射(我没有尝试过)之外,我发现的最佳解决方案是手动修改要跟踪的每个函数,正如我在 Converting OCaml to F#: Is there a simple way to simulate OCaml top-level #trace in F# 中指出的那样,并将结果保存到单独的日志中文件使用NLog。
见:Using NLog with F# Interactive in Visual Studio - Need documentation
另一条路线是查看F# on Mono 的工作,因为那里有很多工作要做,以添加用于 F# 的额外工具。
基本上我发现随着我的 F# 技能增加我的需求 使用调试器或跟踪减少。
目前,当我遇到需要此级别检查的问题时,添加Converting OCaml to F#: Is there a simple way to simulate OCaml top-level #trace in F# 中提到的检查代码有助于解决我的误解。
另外值得注意的是,从 C# 世界到 F# 世界的人们往往期望调试器同样有用。请记住,命令式语言倾向于处理变量中保存的数据,并且调试器用于检查这些变量中的值,而对于函数式编程,至少对我而言,我尽量避免可变值,因此唯一需要的值要检查的是传递给函数的值,而不是其他值,因此减少或消除了对调试器或检查超出问题函数的需要。
【讨论】: