Различаемая метка объединения в строку

#f#

#f#

Вопрос:

учитывая следующее различаемое объединение:

 type A = B of string | C of int
  

Как я могу получить имя конструктора B?

 A.B.ToString()
// would return something like:
val it : string = "FSI_0045 it@109-19"
// when I desire
val it : string = "B"
  

например, с этим типом это работает:

 type D = E | F

D.E.ToString();;
val it : string = "E"
  

Обычно я получаю строковое имя экземпляра DU с помощью

 let stringFromDU (x: 'a) =
  match FSharpValue.GetUnionFields(x, typeof<'a>) with
  | case, _ -> case.Name
  

Но в этом случае у меня нет экземпляра, я просто хочу сериализовать имя метки.

Ответ №1:

Если вы включаете последнюю версию языка, например, путем перехода --langversion:preview в FSI или настройки

 <PropertyGroup>
   <LangVersion>preview</LangVersion>
</PropertyGroup>
  

в вашем .fsproj случае будет работать следующее:

 type A = B of int
let n = nameof A.B
  

Примечание: с F # 5 это будет поддерживаться из коробки 🙂

Комментарии:

1. Спасибо! это должно быть то, что я хочу, однако я все еще не использую предварительный просмотр, поскольку он пока нестабилен. Я использую это: fsharp let rec funName = function | Patterns.NewUnionCase (x, _) -> x.Name | Patterns.Call (None, methodInfo, _) -> methodInfo.Name | Patterns.Lambda (_, expr) -> funName expr | _ -> failwith "Unexpected input" <@ A.B @> |> funName Я переключусь на nameof после того, как F # 5 выйдет. Я нашел это немного плохим, так как я должен предоставить функцию сбоя — .-

2. @CodingEdgar Вы можете использовать функции предварительного просмотра с текущим 4.7 … для меня пока никаких проблем 🙂

3. Я попробую и свяжусь с вами, если все скомпилируется, спасибо!

4. Использовал ваш подход, все скомпилировалось и работало как шарм, спасибо.

Ответ №2:

FSharpValue В вашем примере вы используете FSharp.Reflection пространство имен from . Обратите внимание, что в этой библиотеке есть другой класс для обработки сценариев, в которых вы хотите работать только с типами, FSharpType .

 let cases = FSharpType.GetUnionCases(typeof<A>)
  

Помимо объединений, он также предоставляет помощников для других операций с собственными типами F #.

Комментарии:

1. Да, я использую это для преобразования из string в DU, но я не могу получить имя случая DU с помощью этого, как, я думаю, в желаемом примере выше.

2. Он может дать вам имена всех случаев, но вы правы, он не позволит вам перейти от конструктора случая объединения к его имени. Цитаты были бы правильным инструментом здесь, так, как вы используете их сейчас.