[英]How to leverage power of TextWriterFormat for printfn style in combination with ConditionalAttribute which requires unit result
I set myself to creating a trace function that behaves like sprintf
or printfn
, but is disabled (JIT removes it on call site) for Release builds by using the ConditionalAttribute
.我设置自己创建一个跟踪函数,其行为类似于
sprintf
或printfn
,但通过使用ConditionalAttribute
为发布版本禁用(JIT 在调用站点上将其删除)。
Result so far: I don't think it is possible.到目前为止的结果:我认为这是不可能的。
The problem centers around the fact that when you use the Conditional("DEBUG")
attribute, the function must return unit result.问题围绕这样一个事实:当您使用
Conditional("DEBUG")
属性时,该函数必须返回单位结果。 "Normal" arguments work as they should and the method is properly decorated (EDIT: decorated , yes, but curryable members are not erased , see discussion , must use tuple-form instead): “正常”参数按其应有的方式工作,并且方法已正确装饰(编辑:装饰,是的,但不会删除可咖喱成员,请参阅讨论,必须改用元组形式):
type Trace() =
[<Conditional("DEBUG")>]
static member inline trace msg b = (msg, b) |> ignore
// using it, x is unit
let x = Trace.trace "test" "foo"
(note that, without the ignore
, this won't compile because of the Conditional attribute) (请注意,如果没有
ignore
,由于 Conditional 属性,这将无法编译)
But as soon as I try any variant of the Printf.TextWriterFormat<'T>
, it fails and I don't see a way around it:但是,一旦我尝试
Printf.TextWriterFormat<'T>
任何变体,它就会失败并且我看不到解决方法:
type Trace() =
[<Conditional("DEBUG")>]
static member inline trace msg = printfn msg // inline or not doesn't matter
// using it, x is unit
let x = Trace.trace "hello: %s" "foobar"
This works without the attribute, but with the attribute, it will raise:这在没有属性的情况下工作,但有了属性,它会引发:
This expression was expected to have type
此表达式应具有类型
unit
but here has type但这里有类型
string -> unit
The error is specifically underlining Trace.trace "hello: %s"
.该错误特别强调了
Trace.trace "hello: %s"
。 So it looks like the compiler not recognizing that the whole of the expression results in a unit
, and raises the error because it internally creates a wrapper function that returns string -> unit
, which is not allowed by the rules of the ConditionalAttribute
.所以看起来编译器没有识别出整个表达式结果是一个
unit
,并引发错误,因为它在内部创建了一个返回string -> unit
的包装函数,这是ConditionalAttribute
的规则所不允许的。
When I try to fix it by explicitly specifying :unit
on the function return type, or printfn msg |> ignore
as the body, then I lose the ability to use the text writer format string with type safety, in fact, it won't recognize the second argument on the call-site at all anymore.当我尝试通过在函数返回类型上显式指定
:unit
或printfn msg |> ignore
作为主体来修复它时,我将失去使用具有类型安全性的文本printfn msg |> ignore
格式字符串的能力,事实上,它不会不再识别呼叫站点上的第二个参数。
So, while the whole of the function signature obeys CLR's rules, it seems that the inline functions that F# creates do not, at least not in this specific case.因此,虽然整个函数签名都遵守 CLR 的规则,但 F# 创建的内联函数似乎没有,至少在这种特定情况下没有。
I have tried variants, including kprintf
, sprintf
to see if that helped, but all to no avail.我尝试了变体,包括
kprintf
、 sprintf
,看看是否有帮助,但都无济于事。
Any ideas?有任何想法吗? Or is this one of those situations where you try to lay out a carpet and once you have it properly smoothed in one corner, it bubbles up in the other corner, and vice versa, ie it never fits?
或者这是您尝试铺设地毯的情况之一,一旦您在一个角落适当地平滑它,它就会在另一个角落冒泡,反之亦然,即它永远不会适合?
PS: in case you are wondering why I want it: just trying to create a convenience function that behaves like existing Trace, but with some other functionality going on under the hood. PS:如果您想知道我为什么想要它:只是尝试创建一个行为类似于现有 Trace 的便利函数,但在幕后还有其他一些功能。 What I currently have works, but it just takes a string, not a statically type checked arguments, so it forces users to write something like:
我目前拥有的作品,但它只需要一个字符串,而不是一个静态类型检查参数,所以它迫使用户编写如下内容:
(sprintf "Hello %s" >> Trace.trace) "foobar"
An overloading based version.基于重载的版本。
You might want some more overloads你可能想要更多的重载
#if DEBUG
type Log() =
static member inline log(x) = printfn x
static member inline log(x,y) = printfn x y
#else
type Log =
static member inline log(x) = ()
static member inline log(x,y) = ()
#end
So this works:所以这有效:
open System.Diagnostics
type Log() =
[<Conditional("DEBUG")>]
static member log(x) = printfn x
[<Conditional("DEBUG")>]
static member log(x,y) = printfn x y
you need to switch to the tuple form to allow for overloading and use tuple form as curried things can't be overloaded您需要切换到元组形式以允许重载并使用元组形式,因为柯里化的东西不能重载
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.