2009-10-21 7 views
16

Chcę iterować po elementach w wyliczeniu.Powtarzanie elementów w wyliczeniu w Delphi

Chciałbym móc powiedzieć coś takiego:

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; 

Najbliżej byłem w stanie przyjść to:

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; 

którego używam tak:

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; 

to działa dobrze, z wyjątkiem wymienionych dostaję wygląda następująco (zauważyć dwie ostatnie pozycje):

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

Dwa elementy na końcu nie są oczywiście tym, czego chcę.

Czy istnieje lepszy sposób do iteracji elementów elementu wyliczonego?

Jeśli nie, to czy jest to bezpieczne założenie, że nie będzie zawsze być dokładnie dwa dodatkowe elementy używając mojego obecnego sposobu? Oczywiście jest to nazwa jednostki ... ale co robi symbol "@"? Czy to naprawdę śmieci, czy jest to więcej informacji o typie?

Używam Delphi 2007. Dzięki za wszelkie spostrzeżenia.

Odpowiedz

51

Proste:

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

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

Ok, jestem idiotą. Próbowałem tego wcześniej, ale zostawiłem swój "el" jako liczbę całkowitą i nie zdałem sobie sprawy z mojego błędu. Dziękuję Ci. – JosephStyons

+0

Nadal zastanawiam się, co znaczy "@". – JosephStyons

+3

MaxEnum prawdopodobnie jest błędny; zwracając więcej niż rzeczywistą liczbę wyliczeń. I GetEnumName używa tego błędnego wyniku do analizy wewnętrznych struktur w kodzie. Otrzymujesz losowe fragmenty pamięci poza strukturami wewnętrznymi. –

0

zrobiłem EnumerationEnumerator więc można go używać w 'dla ... w' instrukcji w Delphi. Jednak wówczas czasami generowałby wewnętrzne błędy kompilatora.

Edit:

Udało nam się dostać do pracy w Delphi 2007 i do góry (patrz this blog article i dość ciekawą dyskusję pod nią).

+3

Interesujące! Nigdy nie rozumiałem, dlaczego to nie jest możliwe. – Giel

+0

@Giel: tutaj jest http://wiert.wordpress.com/2009/10/27/delphi-for-in-on-onumerated-data-types/ –

4

Jest dość bardziej skomplikowane niż to, gdy stosuje specjalne wyliczeń ... zobaczmy naprawdę 100% roztwór roboczy o złożonej wyliczeniowej definicję:

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 

Uwagi:

  • Nie wszystkie wyliczone definicje muszą zaczynać się od 0 i być przyległe, można je zdefiniować jak na próbce
  • Zobacz, jak zdefiniowano typ (nie posortowane, nie sąsiednie itp.)
  • Zobacz, jak to zostało dodane stałą tablicę z właściwej kolejności elementów
  • Musi iteracyjne na takiej tablicy, ponieważ kolejność jest stracone i Succ i Pred nie działają prawidłowo na tego rodzaju wyliczeń

Dlaczego go zostało zrobione w ten sposób?:

  • Numeracja celu musi być zachowana i nie przylega
  • Delphi, gdy w tej próbce tworzy typ TmyEnumType przypisanie do niego (9-2 + 1 = 8) elemments (od dolna (2) wyższe jeden (9), tak ważne wartości dla tego typu są z porządkowej 2 do porządkowej 9
  • Funkcje Delphi Succ i Pred tylko zwiększają i zmniejszają o jeden, nie sprawdzają nieciągłego sposobu ich definiowania, więc przypisz wartości, które są poza zakresem, a także traci kolejność definicji

Sztuczka :

  • stwierdzenie ciągłą stałą tablicę z elementów w odpowiedniej kolejności
  • pętli na tej stałej tablicy

Jeśli spróbujesz to inne (logiczny ludzkiego sposobu myślenia), to nie będzie działać (nie Niezależnie od tego czy stosowanie pętli for, while, powtarzać aż itp):

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 

to, co mam przetestowane przez mój własny na Turbo Delphi 2006.

+1

Dlaczego ludzie wciąż strzelają sobie w stopę z - ścisłe wyliczenia? –

3

Możesz użyć Succ (x) i Pred (x), aby przepuścić przez wyliczenie. Ale pamiętaj, aby sprawdzić granice, więc nie próbuj Succ (x) na ostatnim elemencie wyliczenia!

Przykład:

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;