我有一个实用程序函数,它将记录错误消息(包括字符串格式)与引发异常(raise
- 现有异常或使用格式化错误消息调用failwith
相结合,类似于下面的logAndFailWithf函数(虽然实际上它使用的是日志框架,而不是写入文本文件):
let logAndFailWithf exOpt =
let logFile = new StreamWriter("log.txt")
Printf.ksprintf <| fun message ->
try match exOpt with
| Some ex ->
logFile.WriteLine("{0}\r\n{1}", message, ex)
raise <| Exception(message, ex)
| None ->
logFile.WriteLine(message)
failwith message
finally logFile.Close()
val logAndFailWithf : exOpt:#exn option -> (Printf.StringFormat<'b,'c> -> 'b)
如果直接调用此函数可以正常工作,如下例所示:
let s = "123x"
let x = try Int32.Parse s
with | ex -> logAndFailWithf (Some ex) "Failed to parse string s: %s" s
System.Exception: Failed to parse string s: "123x" --->
System.FormatException: Input string was not in a correct format.
at System.Number.StringToNumber(String str, NumberStyles options,
NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal)
at System.Number.ParseInt32(String s, NumberStyles style, NumberFormatInfo info)
但是,在实际场景中,日志记录函数正在传递给另一个函数,该函数在遇到异常时使用它来记录和抛出,类似于以下内容:
let exmaple param1 param2 (log: exn option -> Printf.StringFormat<_,_> -> _) =
let x = try Int32.Parse param1
with | ex -> log (Some ex) "Failed to parse param1: \"%s\"" param1
let y = try Int64.Parse param2
with | ex -> log (Some ex) "Failed to parse param2: \"%s\"" param2
printfn "Successfully Parsed Parameters: param1 = %d; param2 = %d" x y
在这种情况下,编译器会在第二个let绑定(let y = ...
)上报告错误消息:
error FS0001: This expression was expected to have type
'int64'
but here has type
'int'
对于与日志函数的第一次使用类型不同的表达式中的日志函数的任何使用,都会出现这种情况(在上面的示例中,绑定int64
时为y
绑定int
时而不是x
,而我还没有找到一种方法来表达log
参数的类型,它们都匹配{{1}的签名1}}函数在同一函数中用于不同类型的表达式时起作用。
如何将这个隐式泛型函数作为参数传递给其他函数,以便可以在不同类型的表达式中调用它?