Automatically figuring out function name in f#

我是研究僧i 提交于 2021-02-18 11:00:28

问题


If I have a function that is part of a module, and I want a log entry while inside the function,I have to manually print the function namespace and name e.g.

namespace MyModuleNamespace
 module MyModule = 
 let AddTwoNums logger x y =
    logger.Info("MyModuleNamespace.AddTwoNums - Start")
    let res = x+y
    logger.Info("MyModuleNamespace.AddTwoNums - End")
    res

Is there any way I can automatically work out what "MyModuleNamespace.AddTwoNums" is as it is very cumbersome/error prone especially when you have to rename functions and modules during refactoring of code

Even if that cannot be done, is there any way I can automatically work out what "AddTwoNums" is i.e. the function name?


回答1:


There are a couple ways to do this, and I'm not sure which would be the best one for your scenario. One way that I've used in the past is to get the information from the stack trace:

let stackTrace = StackTrace()
let topFrame = stackTrace.GetFrame(0)
let currentFunction = topFrame.GetMethod()
printfn "%s.%s" currentFunction.DeclaringType.Name currentFunction.Name

In order to keep from having to put these lines in every function, you can make an inline function that does this, which will give you the name of the calling function due to the inlining.

let inline getCurrentFunction () =
    let stackTrace = StackTrace()
    let topFrame = stackTrace.GetFrame(0)
    let currentFunction = topFrame.GetMethod()
    sprintf "%s.%s" currentFunction.DeclaringType.Name currentFunction.Name



回答2:


If you don't need the actual namespace / module name or are willing to replace that with the file name, there are special attributes that instruct the compiler to supply corresponding arguments to a function:

open System.Runtime.CompilerServices

type Logger =
    static member Trace(
                        msg: string,
                        [<CallerMemberName>] ?memberName: string,
                        [<CallerFilePath>] ?path: string,
                        [<CallerLineNumberAttribute>] ?line: int) =
        printfn "%s from %s.%s on line %i" msg path.Value memberName.Value line.Value

module Foo =
    let bar() =
        Logger.Trace("hello")

// hello from c:\path\to\Logging.fsx.bar on line 32
Foo.bar()

MS Docs has more to say about Caller Information.

Note that when your run this from within fsi, the line number is only accurate the first time.




回答3:


Probably not what you want but you can extract it with Quotations:

let x<'T> : 'T = Unchecked.defaultof<'T>
<@ AddTwoNums x x x@> 
|> function Microsoft.FSharp.Quotations.Patterns.Call(_,mi,_)-> mi.Name | _ -> "unknown"

Im guessing you want to look at getting the stacktrace: https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.stacktrace?view=netframework-4.7.2



来源:https://stackoverflow.com/questions/52554168/automatically-figuring-out-function-name-in-f

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!