Лучший способ представить параметризованное перечисление в C #? - PullRequest
1 голос
/ 16 сентября 2008

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

См. Пример Ocaml ниже в одном из ответов, следующий код Haxe:

enum Tree {
   Node(left: Tree, right: Tree);
   Leaf(val: Int);
}

Ответы [ 4 ]

7 голосов
/ 16 сентября 2008

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

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

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

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

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

В Haxe вы можете добавлять сложные типы к перечислениям, например, на странице Contrived:

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 в Haxe), тогда как ячейка Cons будет.
Компилятор также может встроить / оптимизировать методы в EmptyCell, так как они ничего не делают, поэтому может быть увеличение скорости по сравнению с просто Cons с его данными члена, установленными в нуль.

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

1 голос
/ 16 сентября 2008

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

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

0 голосов
/ 16 сентября 2008

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

0 голосов
/ 16 сентября 2008

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

...