2009-10-21 3 views
16

Я хочу перебирать элементы в перечислении.Итерации через элементы в перечислении в Delphi

Я хотел бы быть в состоянии сказать что-то вроде этого:

type 
    TWeekdays = (wdMonday, wdTuesday, wdWednesday, wdThursday, wdFriday); 

... 
elementCount := GetElementCount(TypeInfo(TWeekDays)); 

for i := 0 to elementCount - 1 do begin 
    ShowMessage(GetEnumName(TypeInfo(TWeekdays),i)); 
end; 

Ближайший я смог прийти это:

function MaxEnum(EnumInfo: PTypeInfo): integer; 
const 
    c_MaxInt = 9999999; 
var 
    i: integer; 
    s: string; 
begin 
    //get # of enum elements by looping thru the names 
    //until we get to the end. 
    for i := 0 to c_MaxInt do begin 
    s := Trim(GetEnumName(EnumInfo,i)); 
    if 0 = Length(s) then begin 
     Result := i-1; 
     Break; 
    end; 
    end; 
end; 

, который я использую, как это:

procedure TForm1.BitBtn1Click(Sender: TObject); 
var 
    i, nMax: integer; 
begin 
    ListBox1.Clear; 
    nMax := MaxEnum(TypeInfo(TWeekdays)); 
    for i := 0 to nMax do begin 
    ListBox1.Items.Add(GetEnumName(TypeInfo(TWeekdays),i)); 
    end; 
end; 

Это хорошо работает, за исключением того, что список выглядит следующим образом (обратите внимание на последние два предмета):

wdMonday 
wdTuesday 
wdWednesday 
wdThursday 
wdFriday 
Unit1 
'@'#0'ôÑE'#0#0#0#0#0#0#0#0#0#0#0#0#0 <more garbage characters> 

Два предмета в конце, очевидно, не то, что я хочу.

Есть ли лучший способ итерации по элементам перечисляемого типа?

Если нет, то это с уверенностью предположить, что будет всегда ровно два дополнительные элементы, используя мой текущий метод? Очевидно, что это имя группы ... но что такое символ «@»? Это действительно мусор, или это больше информации о типе?

Я использую Delphi 2007. Спасибо за любые идеи.

ответ

51

Простой:

type 
    TWeekdays = (wdMonday, wdTuesday, wdWednesday, wdThursday, wdFriday); 

procedure Test; 
var 
    el: TWeekdays; 
begin 
    for el := Low(TWeekdays) to High(TWeekdays) do 
    ; // 
end; 
+4

Хорошо, я идиот. Я пробовал это раньше, но я оставил свой «el» как целое число и не осознал свою ошибку. Спасибо. – JosephStyons

+0

Мне все еще интересно, что означает «@». – JosephStyons

+3

MaxEnum, вероятно, глючит; возвращая больше, чем фактическое количество перечислений. И GetEnumName использует этот ошибочный результат для анализа внутренних структур в вашем коде. То, что вы получаете, это случайные фрагменты памяти за пределами внутренних структур. –

0

Я сделал EnumerationEnumerator, чтобы вы могли использовать его в 'для ... в' заявление в Delphi. Однако, тогда он иногда генерирует внутренние ошибки компилятора.

Edit:

Управляемый, чтобы заставить его работать в Delphi 2007 и выше, см this blog article (и довольно интересная дискуссия под ним).

+3

Интересно! Я никогда не понимал, почему это невозможно в первую очередь. – Giel

+0

@Giel: здесь http://wiert.wordpress.com/2009/10/27/delphi-for-in-on-enumerated-data-types/ –

4

Это довольно сложнее, чем при использовании специальных перечислений ... давайте посмотрим, действительно 100% рабочего раствора для комплексного определения перечисляемого:

type 
    TmyEnumType=(myEnumTypeA=5,myEnumTypeB=2,myEnumTypeC=9); 
const 
    myEnumTypeOrder:Array[1..3] of TmyEnumType=(myEnumTypeA,myEnumTypeB,myEnumTypeC); 
procedure TForm1.Button1Click(Sender: TObject); 
var 
    myEnumTypeVariable:TmyEnumType; 
begin 
    myEnumTypeVariable:=Low(TmyEnumType); 
    for myEnumTypeVariable in myEnumTypeOrder 
    do begin 
      ShowMessage(IntToStr(Ord(myEnumTypeVariable))); // Sample code to show enum integer value 
      // Extra code you neede 
     end; 
end; 
// This code shows three messages in this secuence: 5, 2, 9 
// Correct number of elements and in the correct order 

Примечания:

  • Не все перечислимые определения должны начинаться с 0 и быть смежными, могут быть определены как на образце
  • Посмотрите, как этот тип был определен (не отсортирован, не смежен и т. д.)
  • Посмотрите, как он был добавлен постоянный массив с правильным порядком элементов
  • должны итерацию на таком массиве, поскольку порядок теряется и Succ и Pred не работают должным образом на такого рода перечислений

Почему это так было сделано?:

  • перечисленный порядок должен быть сохранен и не смежные
  • Delphi, когда на этом образце создает тип TmyEnumType назначить на него (9-2 +-= 8) elemments (от нижнего (2) выше, один (9), поэтому допустимые значения для такого типа относятся от порядкового номера 2 к порядку 9
  • Функции Delphi Succ и Pred только увеличиваются и уменьшаются на единицу, не проверяйте несмежный способ его определения, поэтому присваивайте значения, которые вне диапазона, а также потерять порядок определения

The Trick :

  • Объявите непрерывный постоянный массив с элементами в правильном порядке
  • Loop на этом константный массиве

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

type 
    TmyEnumType=(myEnumTypeA=5,myEnumTypeB=2,myEnumTypeC=9); 
procedure TForm1.Button1Click(Sender: TObject); 
var 
    myEnumTypeVariable:TmyEnumType; 
begin 
    for myEnumTypeVariable:=Low(TmyEnumType) to High(TmyEnumType); 
    do begin 
      ShowMessage(IntToStr(Ord(myEnumTypeVariable))); // Sample code to show enum integer value 
      // Extra code you neede 
     end; 
end; 
// This code shows eight messages in this secuence: 2, 3, 4, 5, 6, 7, 8, 9 
// Inorrect number of elements and in order is lost 

это то, что я испытал на моем собственном на Turbo Delphi 2006.

+1

Почему люди продолжают стрелять в ногу, - смежные перечисления? –

3

Вы можете использовать Succ (x) и Pred (x) для прокрутки перечисления. Но не забудьте проверить границы, чтобы не попробовать Succ (x) в последнем элементе перечисления!

Пример:

type 
    TWeekdays = (wdMonday, wdTuesday, wdWednesday, wdThursday, wdFriday); 

procedure Test; 
var 
    val: TWeekdays; 
begin 
    val := wdTuesday; 
    val := Succ(val); // wdWednesday 

    val := wdFriday; 
    val := Pred(val); // wdThursday, 
end; 
Смежные вопросы