F# StructuredFormatDisplayAttribute
Совсем маленький пост про совсем неизвестный атрибут StructuredFormatDisplayAttribute
из состава стандартной бибилиотеки F#. Данный атрибут позволяет управлять логикой преобразования значений к текстовому виду согласно спецификатору формата %A
(то есть при использовании функций printf
, sprintf
и других из модуля Printf
) и отображению значений данного типа в интерактивной консоли F#. Обычно, определяя пользовательский тип:
type Person(name: string, age: int, money: decimal) =
member __.Name = name
member __.Age = age
member __.Money = money
let alex = Person("Alex", 22, 200000m)
И создавая его экземпляры, вы будете видеть их в консоли F# interactive следующим образом:
val alex : Person = FSI.Person
Однако, переопределив метод System.Object.ToString()
, можно наблюдать за внутренним состоянием объектов и в интерактивной консоли, так как F# interactive и %A
используют переопределение ToString()
, если таковое имеется:
type Person(name: string, age: int, money: decimal) =
member __.Name = name
member __.Age = age
member __.Money = money
override __.ToString() =
sprintf "Person(%s, %d, %O)" name age money
let alex = Person("Alex", 22, 200000m)
Вывод:
val alex : Person = Person(Alex, 22, 200000M)
Тем не менее, тот текст, который возвращает ToString()
, и который вы хотите наблюдать в консоли F# interactive или при выводе в формате %A
, может отличаться. На этот случай и может понадобится атрибут [<StructuredFormatDisplay>]
, которые позволяет задать формат вывода. Формат задаётся строкой вида "Префикс {ИмяСвойства} Постфикс"
, где Префикс
и Постфикс
- любой необязательный текст, а ИмяСвойства
- имя свойства, определённого в данном типе или его базовом классе:
[<StructuredFormatDisplay("Person (with Name='{Name}')")>]
type Person(name: string, age: int, money: decimal) =
member __.Name = name
member __.Age = age
member __.Money = money
override __.ToString() =
sprintf "Person(%s, %d, %O)" name age money
let alex = Person("Alex", 22, 200000m)
Вывод принимает вид:
val alex : Person = Person (with Name='Alex')
Обратите внимание, что использовать можно имя только одного свойста, в строке формата нельзя использовать символы {
и }
(даже экранируя как {{
и }}
). Поддерживается доступ к свойствам, объявленным с модификатором доступа private
.