Типы C # для пустых случаев распознавания F # - PullRequest
0 голосов
/ 01 сентября 2018

Я получаю доступ к объединению, отличающемуся от F #, используя C # и пытаюсь использовать оператор switch в случаях объединения. Это прекрасно работает для значений, которые имеют хотя бы одно поле, но не для пустых значений, поскольку для них не создан соответствующий класс, только свойство. Рассмотрим следующий F # дискриминируемый союз.

type Letter = A of value:int | B of value:string | C | D

В C # у меня есть следующий оператор switch внутри функции, которая имеет букву аргумента типа Letter:

switch (letter)
{
    case A a: Console.WriteLine(a.value); break;
    case B b: Console.WriteLine(b.value); break;
    default:
        if (letter.IsC) Console.WriteLine("C");
        else if (letter.IsD) Console.WriteLine("D");
}

Случай по умолчанию обрабатывает случаи, когда значение объединения пусто. Я бы предпочел:

switch (letter)
{
    case A a: Console.WriteLine(a.value); break;
    case B b: Console.WriteLine(b.value); break;
    case C c: Console.WriteLine("C"); break;
    case D d: Console.WriteLine("D"); break;
}

Но это не работает, потому что имена типов C и D не существуют - C и D являются свойствами, а не типами. Я могу обойти это, дав C и D поле типа unit, но это не очень элегантно. Почему типы создаются только для непустых значений различаемых объединений и каков лучший обходной путь?

Ответы [ 3 ]

0 голосов
/ 01 сентября 2018
switch (letter)
{
    case A a: Console.WriteLine(a.value); break;
    case B b: Console.WriteLine(b.value); break;
    case Letter l when l == C: Console.WriteLine("C"); break;
    case Letter l when l == D: Console.WriteLine("D"); break;
}

Пустые распознаваемые объединения используют шаблон синглтона с тегом, переданным через конструктор, поэтому свойство C назначается новой букве (0), а D - новой букве (1), где буква - это соответствующий класс C #. Первая часть оператора case всегда будет иметь значение true, поскольку буква имеет тип Letter. В предложениях where указано, что буква должна быть равна экземпляру синглтона Letter, который соответствует пустым значениям разграниченного объединения C и D.

0 голосов
/ 01 сентября 2018

Если вы не возражаете добавить немного сложности к своему типу, вы можете определить свой тип F # следующим образом:

type Letter = A of value:int | B of value:string | C of unit | D of unit

Сделав это, вы можете сопоставить шаблон в C # следующим образом:

switch (letter)
{
    case A a: Console.WriteLine("A"); break;
    case B b: Console.WriteLine("B"); break;
    case C _: Console.WriteLine("C"); break;
    case D _: Console.WriteLine("D"); break;
}
0 голосов
/ 01 сентября 2018

Я не думаю, что угадывание, почему F # DU были реализованы так, как в спецификации языка 8.5.4 Скомпилированная форма типов объединения для использования с другими языками CLI , было бы крайне важно при использовании F # DU из C #.

Хорошим дизайном для такого сценария взаимодействия было бы избегать использования «сырых» DU, вместо этого скрывая эту деталь реализации за некоторым интерфейсом, который F # предоставил бы другим языкам CLI.

В нескольких случаях (например, этот и этот ) вопрос с использованием F # DU из C # был рассмотрен на SO, и были даны рекомендации, как это сделать правильный путь .

Но если вы настаиваете на неправильном пути , когда ваш C # полагается на специфику реализации F # DU, то подойдет следующий взлом C #:

namespace ConsoleApp1
{
    class Program {

        private static void unwindDU(Letter l)
        {
            switch (l.Tag)
            {
                case Letter.Tags.A: Console.WriteLine(((Letter.A)l).value); break;
                case Letter.Tags.B: Console.WriteLine(((Letter.B)l).value); break;
                case Letter.Tags.C: Console.WriteLine("C"); break;
                case Letter.Tags.D: Console.WriteLine("D"); break;
            }
        }

        static void Main(string[] args)
        {
            unwindDU(Letter.NewA(1));
            unwindDU(Letter.C);
        }
    }
}

Будучи исполненным, он вернет

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