简体   繁体   English

如何将 TextWriterFormat 的强大功能用于 printfn 样式,并结合需要单位结果的 ConditionalAttribute

[英]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 .我设置自己创建一个跟踪函数,其行为类似于sprintfprintfn ,但通过使用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.当我尝试通过在函数返回类型上显式指定:unitprintfn 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.我尝试了变体,包括kprintfsprintf ,看看是否有帮助,但都无济于事。

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

update:更新:

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM