Лучший способ представить параметризованное перечисление в С#?

StackOverflow https://stackoverflow.com/questions/66819

  •  09-06-2019
  •  | 
  •  

Вопрос

Есть ли хорошие решения для представления параметризованного перечисления в C# 3.0?Я ищу что-то вроде OCaml или Хаксе имеет.На данный момент я могу думать только об иерархии классов с простым полем перечисления для удобного переключения, может быть, есть идеи получше?

См. пример Ocaml ниже в одном из ответов, ниже приведен код Haxe:

enum Tree {
   Node(left: Tree, right: Tree);
   Leaf(val: Int);
}
Это было полезно?

Решение

Не будучи знакомым с OCaml или Haxe и не будучи достаточно умным, чтобы понять другие объяснения, я пошел и поискал Документация по перечислению Haxe - бит «Параметры типа перечисления» внизу, по-видимому, является соответствующей частью.

Мое понимание, основанное на этом, следующее:

«Обычное» перечисление — это, по сути, значение, которое ограничено тем, что вы определили в определении перечисления.Пример С#:

enum Color{ Red, Green, Yellow, Blue };
Color c = Color.Red;

c может быть либо Red, Green, Yellow, или Blue, но ничего больше.

В Haxe вы можете добавлять сложные типы в перечисления. Надуманный пример с их страницы:

enum Cell<T>{ 
  empty; 
  cons( item : T, next : Cell<T> )
}

Cell<int> c = <I don't know>;

Что это появляется иметь в виду, что c ограничивается буквальным значением empty (например, наши старомодные перечисления C#), или это также может быть сложный тип. cons(item, next), где item это T и next это Cell<T>.

Если вы никогда не использовали это, похоже, что он, вероятно, генерирует некоторые анонимные типы (например, как это делает компилятор C#, когда вы это делаете). new { Name='Joe'}.
Всякий раз, когда вы «обращаетесь» к значению перечисления, вы должны объявить item и next когда вы это сделаете, и похоже, что они привязаны к временным локальным переменным.

Пример Haxe. Вы можете видеть, что «next» используется как временная локальная переменная для извлечения данных из анонимной структуры cons:

switch( c ) {
  case empty : 0;
  case cons(item,next): 1 + cell_length(next);
}

Честно говоря, это поразило меня, когда я «нажал» на то, что он, казалось, делал.Это кажется невероятно мощным, и я понимаю, почему вам нужна подобная функция в C#.

Перечисления C# во многом аналогичны перечислениям C/++, из которых они изначально были скопированы.По сути, это хороший способ сказать #define Red 1 поэтому компилятор может выполнять сравнения и сохранять целые числа вместо строк при передаче Color предметы вокруг.

Моя попытка сделать это на C# заключалась бы в использовании дженериков и интерфейсов.Что-то вроде этого:

public interface ICell<T> {
   T Item{ get; set; }
   ICell<T>{ get; set; }
}

class Cons<T> : ICell<T> {
  public T Item{ get; set; } /* C#3 auto-backed property */
  public Cell<T> Next{ get; set; }
}

class EmptyCell<T> : ICell<T>{
  public T Item{ get{ return default(T); set{ /* do nothing */ }; }
  public ICell<T> Next{ get{ return null }; set{ /* do nothing */; }
}

Тогда вы могли бы иметь List<ICell<T>> который будет содержать элементы и следующую ячейку, и вы можете вставить EmptyCell в конце (или просто иметь Next ссылка явно установлена ​​в ноль).Преимущества заключаются в том, что EmptyCell не содержит переменных-членов, для него не потребуется места для хранения (например, empty в Хаксе), тогда как Cons клетка бы.
Компилятор также может встроить/оптимизировать методы в EmptyCell поскольку они ничего не делают, поэтому скорость может быть выше, чем просто наличие Cons с его данными о членах, установленными на ноль.

Я действительно не знаю.Я был бы рад любым другим возможным решениям, поскольку своим не особенно горжусь :-)

Другие советы

Использовать сорт это со статическими свойствами для представления значений перечисления.При желании вы можете использовать закрытый конструктор, чтобы заставить все ссылки на класс проходить через статическое свойство.

Взгляните на System.Drawing.Color сорт.Он использует этот подход.

C# (насколько мне известно, платформа .NET в целом) не поддерживает параметризованные перечисления, как это делает Java.При этом вы можете посмотреть Атрибуты.Некоторые функции, на которые способны перечисления Java, в некоторой степени реализуемы с помощью атрибутов.

Что плохого в том, чтобы просто использовать для этого класс?Это уродливо, но именно так поступали Java-разработчики, пока у них не появилась интегрированная в язык поддержка Enum!

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top