Как использовать возможности 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
вам нужно переключиться на форму кортежа, чтобы учесть перегрузку, и использовать форму кортежа, поскольку карри не может быть перегружен