Как использовать возможности TextWriterFormat для стиля printfn в сочетании с ConditionalAttribute, который требует единичного результата

Я настроил себя на создание функции трассировки, которая ведет себя как sprintf или же printfn, но отключено (JIT удаляет его на сайте вызовов) для сборок Release с использованием ConditionalAttribute,

Результат пока: я не думаю, что это возможно.

Проблема заключается в том, что когда вы используете Conditional("DEBUG") атрибут, функция должна возвращать результат единицы измерения. "Нормальные" аргументы работают как надо, и метод правильно оформлен:

type Trace() =    
    [<Conditional("DEBUG")>]
    static member inline trace msg b = (msg, b) |> ignore

// using it, x is unit
let x = Trace.trace "test" "foo"

(обратите внимание, что без ignore это не скомпилируется из-за атрибута Conditional)

Но как только я попробую любой вариант 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"

Это работает без атрибута, но с атрибутом это вызовет:

Ожидалось, что это выражение будет иметь тип
unit
но тут есть тип
string -> unit

Ошибка конкретно подчеркивает Trace.trace "hello: %s", Таким образом, похоже, что компилятор не признает, что все выражение приводит к unit и вызывает ошибку, потому что внутренне создает функцию-обертку, которая возвращает string -> unit, что не допускается правилами ConditionalAttribute,

Когда я пытаюсь это исправить, явно указав :unit на тип возвращаемого значения функции, или printfn msg |> ignore как тело, тогда я теряю возможность использовать строку формата текстового редактора с типом безопасности, фактически, он больше не будет распознавать второй аргумент на сайте вызова.

Таким образом, хотя вся сигнатура функции подчиняется правилам CLR, создается впечатление, что встроенные функции, создаваемые F#, этого не делают, по крайней мере, в данном конкретном случае.

Я пробовал варианты, в том числе kprintf, sprintf чтобы увидеть, помогло ли это, но все безрезультатно.

Есть идеи? Или это одна из тех ситуаций, когда вы пытаетесь разложить ковер, и если вы правильно сглаживаете его в одном углу, он пузырится в другом, и наоборот, то есть он никогда не подходит?


PS: на тот случай, если вам интересно, почему я этого хочу: просто пытаюсь создать вспомогательную функцию, которая ведет себя как существующая трассировка, но с некоторыми другими функциями, происходящими под капотом. То, что у меня сейчас есть, работает, но оно просто принимает строку, а не статически проверенные аргументы типа, поэтому заставляет пользователей писать что-то вроде:

(sprintf "Hello %s" >> Trace.trace) "foobar"

1 ответ

Решение

Перегрузочная версия.

Вы могли бы хотеть больше перегрузок

#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

Обновить:

Так что это работает:

open System.Diagnostics
type Log() =
    [<Conditional("DEBUG")>]  
    static member log(x) = printfn x
    [<Conditional("DEBUG")>]
    static member log(x,y) = printfn x y

вам нужно переключиться на форму кортежа, чтобы учесть перегрузку, и использовать форму кортежа, поскольку карри не может быть перегружен

Другие вопросы по тегам