Reputation: 58795
I want to iterate through the items in an enumeration.
I'd like to be able to say something like this:
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;
The closest I've been able to come is this:
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;
Which I use like this:
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;
That works well, except the list I get looks like this (notice the last two items):
wdMonday
wdTuesday
wdWednesday
wdThursday
wdFriday
Unit1
'@'#0'ôÑE'#0#0#0#0#0#0#0#0#0#0#0#0#0 <more garbage characters>
The two items at the end are obviously not what I want.
Is there a better way to iterate through the elements of an enumerated type?
If not, then is it safe to assume that there will always be exactly two extra items using my current method? Obviously one is the Unit name... but what is the "@" symbol doing? Is it really garbage, or is it more type information?
I'm using Delphi 2007. Thanks for any insights.
Upvotes: 26
Views: 33860
Reputation: 21231
This example compiles on Delphi Sydney (10.4)
type
TDay = (Mon=1, Tue, Wed, Thu, Fri, Sat, Sun); // Enumeration values
var
day : TDay; // Enumeration variable
begin
for day := Mon to Fri do
Caption:= IntToStr(ord(day));
end;
( http://www.delphibasics.co.uk/Article.asp?Name=Sets )
Upvotes: 1
Reputation: 6645
You can use Succ(x) and Pred(x) to loop through an enumeration. But remember to check for boundaries so you don't try Succ(x) on the last element in the enumeration!
Example:
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;
Upvotes: 4
Reputation: 101
It is quite more complex than that, when used special enumerations... let's see a really 100% working solution for a complex enumerated definition:
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
Notes:
Why it has been done like that?:
TmyEnumType
assign to it (9-2+1=8) elemments (from lower one (2) to higher one (9), so valid values for such type are from ordinal 2 to ordinal 9The Trick:
If you try this other (logical human way of thinking) it will not work (no matter if use for loop, while loop, repeat until, etc):
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
That is what i have tested by my own on Turbo Delphi 2006.
Upvotes: 10
Reputation: 24523
I made an EnumerationEnumerator so you could use it in the 'for ... in' statement in Delphi. However, back then it would sometimes generate internal compiler errors.
Edit:
Managed to get it to work in Delphi 2007 and up, see this blog article (and the quite interesting discussion under it).
Upvotes: 1
Reputation: 26850
Simple:
type
TWeekdays = (wdMonday, wdTuesday, wdWednesday, wdThursday, wdFriday);
procedure Test;
var
el: TWeekdays;
begin
for el := Low(TWeekdays) to High(TWeekdays) do
; //
end;
Upvotes: 69