问题
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