【问题标题】:wrap all module's functions with a decorator programmatically以编程方式用装饰器包装所有模块的功能
【发布时间】:2014-02-26 12:21:51
【问题描述】:

需要追踪。装饰器应该打印函数名、参数值和返回值。与其每次都为每个函数编写一个装饰器,不如以编程方式实现这一点。

【问题讨论】:

  • 查看 AOP 解决方案,例如PostSharp。

标签: f# wrapper decorator trace


【解决方案1】:

可以通过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)

但是在这种情况下,没有一种简单的方法可以以编程方式检索函数名称。

另一种选择可能是开发一个类型提供程序,它将程序集路径作为参数并提供所有成员的包装版本。

【讨论】:

  • 太棒了。但我必须重写最初的 f。是否有可能进行简单的替换 f -> wrapperFunction f?
  • 请注意,为了安全起见,您可能需要将 [<MethodImpl(MethodImplOptions.NoInlining)>] 放在包含对 log 的调用的方法上(否则它可能被内联到自己的调用者中,从而导致误导性跟踪) .
  • @OlegLeonov 为了减少视觉干扰,添加一些一元运算符,例如let (!) = wrap
【解决方案2】:

我之前也有同样的愿望,发现目前没有针对 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# 世界的人们往往期望调试器同样有用。请记住,命令式语言倾向于处理变量中保存的数据,并且调试器用于检查这些变量中的值,而对于函数式编程,至少对我而言,我尽量避免可变值,因此唯一需要的值要检查的是传递给函数的值,而不是其他值,因此减少或消除了对调试器或检查超出问题函数的需要。

【讨论】:

  • 非常感谢您的详细回答。
猜你喜欢
  • 2018-05-24
  • 2018-06-02
  • 2015-07-07
  • 1970-01-01
  • 2014-12-29
  • 2022-10-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多