Прохождение нерегулярного перечисления в Delphi

1) Кто-нибудь знает, можно ли перебрать нерегулярное перечисление в Delphi (XE)?

Цикл по обычному перечислению - это нормально. Из Основы Delphi:

var
  suit : (Hearts, Clubs, Diamonds, Spades);
begin
// Loop 3 times
For suit := Hearts to Diamonds do
   ShowMessage('Suit = '+IntToStr(Ord(suit)));
end;

Но если 'костюм' вместо этого объявлен как

var
  suit : (Hearts=1, Clubs, Diamonds=10, Spades);

петли 10 раз. Не удивительно, но я хотел бы зациклить 3. Единственное решение, которое я нашел до сих пор, - это преобразование перечисления в набор и использование цикла for ... in, как в delphi.about.com.

Итак, если ответ на вопрос 1) отрицательный, то:
2) Как преобразовать из перечисления в набор в Delphi?

Контекст, в котором я его использую, представляет собой компонентный массив полей редактирования (TEdit) с нерегулярной нумерацией (edit1, edit5, edit7, edit3, ...). Хотя можно переупорядочить все поля редактирования, это устраняет причину использования перечисления как гибкого способа добавления поля редактирования в середине перечисления.


person Truls    schedule 09.11.2010    source источник
comment
Почему вы не можете использовать какого-нибудь TList потомка и перебирать его?   -  person Ignacio Vazquez-Abrams    schedule 09.11.2010
comment
Перечисление будет использоваться как индекс в массивах TLabels, TEdits и Strings, чтобы я мог использовать StringArray [Job]: = Editbox [Job]. TList мог бы работать, но цель заключалась в том, чтобы упростить чтение исходного кода за счет использования (нерегулярных) перечислений в качестве индексов - например, HashMap в Java. Что я вижу сейчас, вероятно, не сработает ...   -  person Truls    schedule 09.11.2010
comment
Вы пробовали использовать XEs RTTI? Обычный RTTI от блока TypInfo с треском проваливается. Очевидно, вы не можете получить TypeInfo() при нерегулярном перечислении, я тоже пробовал с набором, и это дало мне нарушения доступа.   -  person Jens Mühlenhoff    schedule 09.11.2010
comment
Я только недавно начал использовать Delphi XE (и Delphi) и не копался в RTTI. Просто использовал его для преобразования Enum в String: GetEnumName (TypeInfo (TparameterList)), но это был обычный Enum.   -  person Truls    schedule 09.11.2010
comment
Здорово! Кстати впечатлен тем, как работает Stackoverflow с точки зрения помощи разработчикам в решении проблем. Сегодня опубликовал вопрос, сегодня решен :)   -  person Truls    schedule 09.11.2010


Ответы (6)


У меня сейчас нет компилятора Delphi под рукой, но я думаю, что подход gabr можно значительно улучшить, выполнив

type
  TSuit = (Hearts = 1, Clubs, Diamonds = 10, Spades);

const
  Suits: array[0..3] of TSuit = (Hearts, Clubs, Diamonds, Spades);

Кто знает, может, он даже не компилируется.

person Andreas Rejbrand    schedule 09.11.2010
comment
Протестировал это, и он работает! Спасибо. Если кто-нибудь знает, можно ли избежать повторения перечисления, я был бы рад узнать. - person Truls; 09.11.2010

Я всегда использую

var
  s: TSuit;
begin
  for s := Low(TSuit) to High(TSuit) do
    {something};
end;
person Roger D.    schedule 22.04.2011
comment
Это отлично работает, если перечисление является регулярным, то есть последовательными числами, однако ключом здесь было непоследовательное перечисление. - person Truls; 28.04.2011

Цикл с использованием Ord (Hearts) в Ord (Spades)?

person Pavan    schedule 09.11.2010
comment
Я думаю, что Ord (Hearts) в Ord (Spades) будет повторяться 11 раз, а не 3, как я хочу. - person Truls; 09.11.2010

Грязный вариант, полезный для небольших перечислений:

type
  TSuit = (Hearts = 1, Clubs, Diamonds = 10, Spades);
var
  Suit: TSuit;
begin
  for Suit in [Hearts, Clubs, Diamonds] do
    WriteLn(Ord(Suit));

Хорошо работает в Delphi 2007. Не знаю о старых версиях. Имейте в виду, что использование for Suit in [Hearts..Diamonds] do имеет ту же проблему, что и ваш цикл.
Кстати, я использую WriteLn(), потому что я тестировал это в консольном приложении. :-)

person Wim ten Brink    schedule 09.11.2010
comment
Спасибо за подсказку, буду иметь это в виду. Однако, поскольку в этом случае около 30 элементов, я буду использовать константный подход, предложенный в принятом ответе. - person Truls; 10.11.2010
comment
Что ж, даже с 30 элементами вы все равно сможете скопировать / вставить диапазон из его исходного объявления и назначить набор некоторой константе, которую вы повторно используете для всех своих циклов. У него есть дополнительный бонус: вы можете пропускать элементы между начальным и конечным элементом. - person Wim ten Brink; 10.11.2010

Следует понимать (а часто и не так), что в тот момент, когда вы вводите жесткие порядковые присваивания в перечисление, оно перестает быть перечислимым типом Паскаля - он просто становится «мешком констант», что не то же самое. вещь. Это то, что C-программисты называют перечислениями. Однако перечислимый тип Паскаля является ORDINAL по всем критериям: он имеет дискретные последовательные значения, которые значимо реагируют на базовые операции ORD, PRED, SUCC. Перечисления в C этого не делают, как и перечисления в Паскале, если вы принудительно разделяете порядковые номера.

ПО ЭТОМУ причина того, что RTTI Delphi в основном отказывается возвращать информацию о типе после того, как это было сделано. По сути, это тип tkUnknown, и его следует рассматривать как «мешок» констант времени компиляции. Только потому, что он все еще на словах изображает порядковый номер и имеет (иногда шаткую) поддержку для использования в наборах, люди приходят к выводу, что он по-прежнему должен вести себя как правильный перечислимый тип. Лучше просто понять, что это такое на самом деле: намек на перечисляемые значения в C. Избегайте смешивания метафор кодирования!

Если вы сделаете это, то ваше решение станет очевидным: вы используете перечислимый тип (правильный) для индексации соответствующего массива КОНСТАНТ. Затем вы можете сделать порядковые номера такими, какими захотите, и перечисления сохранят свои полные определения RTTI как правильное перечисление. Итак: ваш ENUMERATED TYPE содержит правильные неизмененные порядковые значения. Вы получаете свои забавные числа, индексируя массив констант с помощью enumeration -ergo array [MyEnums] of byte = (1,3,8,22,99, что угодно)

person Alex T    schedule 15.03.2016

person    schedule
comment
Спасибо за предложение. Поскольку в моем перечислении около 30 элементов, я надеялся избежать ручной инициализации. Но если ярлыков нет, я попробую. - person Truls; 09.11.2010