F #: Как получить тип экземпляра пустого дискриминационного объединения, используя Reflection? - PullRequest
1 голос
/ 09 июня 2019

Я читаю ответы на эти вопросы:

Но я обнаружил кое-что удивительное в базовом типе дискриминационных союзов:

type Union1 =
    | A
    | B 

type Union2 =
    | A
    | B of int

[<EntryPoint>]
let main argv =
    printfn "%A" (Union1.A.GetType())
    printfn "%A" (Union1.B.GetType())

    printfn "%A" (Union2.A.GetType())
    printfn "%A" (Union2.B(32).GetType())
    0
Program+Union1
Program+Union1
Program+Union2+_A
Program+Union2+B

Отсюда мой вопрос, как я могу различить случай на основе типа, когда случай пустой?

1 Ответ

7 голосов
/ 09 июня 2019

Невозможно провести различие между двумя случаями объединения без параметров, основанных на типе, поскольку их тип в скомпилированном коде .NET одинаков. Вы можете увидеть, что это так, слегка подправив свой пример:

type Union1 = A | B     
Union1.A.GetType() = Union1.B.GetType() // Returns 'true'

Компилятор F # компилирует Union1 как класс с числовым полем Tag. Для случаев без дополнительных параметров, таких как A и B здесь, он просто создаст экземпляр Union1 и установит для поля Tag значение 0 или 1.

Если у вас есть объединение с дополнительными параметрами, тогда компилятор генерирует новый унаследованный класс, который затем сохраняет значения этих параметров (поэтому вы получаете другой тип для Union2.B).

С точки зрения F # значения различаемого объединения имеют одинаковый тип (даже если способ компиляции DU означает, что тип может иногда быть унаследованным классом), поэтому нет никаких оснований ожидать, что вы сможете различайте случаи по типу - если у вас есть такой случай, когда он вам нужен, вам, вероятно, следует пересмотреть свой подход.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...