Itérer dans les éléments d'une énumération dans Delphi
Question
Je souhaite parcourir les éléments d'une énumération.
J'aimerais pouvoir dire quelque chose comme ceci:
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;
Voici ce que j'ai pu voir de plus près:
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;
Ce que j'utilise comme ceci:
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;
Cela fonctionne bien, sauf que la liste que je reçois ressemble à ceci (remarquez les deux derniers éléments):
wdMonday
wdTuesday
wdWednesday
wdThursday
wdFriday
Unit1
'@'#0'ôÑE'#0#0#0#0#0#0#0#0#0#0#0#0#0 <more garbage characters>
Les deux éléments à la fin ne sont évidemment pas ce que je veux.
Existe-t-il un meilleur moyen de parcourir les éléments d'un type énuméré?
Si ce n'est pas le cas, est-il prudent de supposer que toujours seront exactement deux éléments supplémentaires utilisant ma méthode actuelle? Il est évident que l’un est le nom de l’unité ... mais quel est le "@"? symbole faisant? Est-ce vraiment une foutaise, ou est-ce plus d'informations de type?
J'utilise Delphi 2007. Merci pour vos idées.
La solution
Simple:
type
TWeekdays = (wdMonday, wdTuesday, wdWednesday, wdThursday, wdFriday);
procedure Test;
var
el: TWeekdays;
begin
for el := Low(TWeekdays) to High(TWeekdays) do
; //
end;
Autres conseils
C’est beaucoup plus complexe que cela, lorsqu’on utilise des énumérations spéciales ... voyons une solution qui fonctionne vraiment à 100% pour une définition énumérée complexe:
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:
- Toutes les définitions énumérées ne doivent pas nécessairement commencer par 0 et être contiguës; elles peuvent être définies comme dans l'exemple
- Voir comment le type a été défini (pas trié, pas contigu, etc ...)
- Voir comment il a été ajouté un tableau constant avec le bon ordre des éléments
- Doit itérer sur un tel tableau car l'ordre est perdu et Succ et Pred ne fonctionnent pas correctement avec ce type d'énumérations
Pourquoi cela a-t-il été fait comme ça?:
- L'ordre énuméré doit être conservé et il n'est pas contigu
- Delphi, quand sur cet exemple crée le type
TmyEnumType
, lui assigne (9-2 + 1 = 8) des éléments (du plus bas (2) au plus élevé (9), ainsi les valeurs valides pour ce type les types vont de l'ordinal 2 à l'ordinal 9 - Les fonctions Delphi Succ et Pred n'augmentent et ne décroissent que d'une unité; ne recherchez pas de manière non-contiguë de la définir. Attribuez donc des valeurs hors de la portée et perdez également l'ordre de définition
Le tour:
- Déclarer un tableau constant contigu avec des éléments dans le bon ordre
- Boucle sur ce tableau constant
Si vous essayez cet autre moyen de penser (logique), cela ne fonctionnera pas (peu importe si vous l'utilisez pour boucle, boucle en boucle, répétez jusqu'à ce que, 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
C’est ce que j’ai testé par moi-même sur Turbo Delphi 2006.
Vous pouvez utiliser Succ (x) et Pred (x) pour parcourir une énumération en boucle. Mais souvenez-vous de vérifier les limites pour ne pas essayer Succ (x) sur le dernier élément de l'énumération!
Exemple:
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;
J'ai créé un EnumerationEnumerator afin que vous puissiez l'utiliser dans l'instruction 'for ... in' de Delphi. Cependant, à l’époque, cela engendrait parfois des erreurs de compilation internes.
Modifier:
Si vous avez réussi à le faire fonctionner dans Delphi 2007 et versions ultérieures, voir cet article de blog (et la discussion assez intéressante qui s’y rapporte).