Совсем маленький пост про совсем неизвестный атрибут 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.