Iterar a través de elementos en una enumeración en Delphi
enums (4)
Quiero iterar a través de los elementos en una enumeración.
Me gustaría poder decir algo como esto:
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;
Lo más cerca que he podido venir es esto:
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;
Que utilizo así:
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;
Eso funciona bien, excepto que la lista que recibo se parece a esto (observe los últimos dos artículos):
wdMonday
wdTuesday
wdWednesday
wdThursday
wdFriday
Unit1
''@''#0''ôÑE''#0#0#0#0#0#0#0#0#0#0#0#0#0 <more garbage characters>
Los dos elementos al final obviamente no son lo que quiero.
¿Hay una mejor manera de iterar a través de los elementos de un tipo enumerado?
De no ser así, ¿es seguro asumir que siempre habrá exactamente dos elementos adicionales con mi método actual? Obviamente, uno es el nombre de la unidad ... pero ¿qué hace el símbolo "@"? ¿Es realmente basura, o es más información de tipo?
Estoy usando Delphi 2007. Gracias por cualquier información.
Es bastante más complejo que eso, cuando se usan enumeraciones especiales ... veamos una solución realmente funcional al 100% para una definición enumerada compleja:
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
Notas:
- No todas las definiciones enumeradas deben comenzar con 0 y ser contiguas, se pueden definir como en la muestra
- Vea cómo se ha definido el tipo (no ordenado, no contiguo, etc.)
- Vea cómo se ha agregado una matriz constante con el orden correcto de los elementos.
- Debe iterar en dicha matriz ya que el orden se pierde y Succ y Pred no funcionan correctamente en ese tipo de enumeraciones
¿Por qué se ha hecho así ?:
- El orden enumerado debe conservarse y no es contiguo.
- Delphi cuando en esa muestra crea el tipo
TmyEnumType
asigna (9-2 + 1 = 8) elementos (de uno inferior (2) a uno superior (9), por lo que los valores válidos para dicho tipo son del ordinal 2 al ordinal 9 - Las funciones de Delphi Succ y Pred solo aumentan y disminuyen en uno, no comprueban la forma no contigua de definirlo, así que asigna valores que están fuera de alcance y también pierde el orden de definición
El truco:
- Declare una matriz constante contigua con elementos en el orden correcto
- Bucle en esa matriz constante
Si lo intentas con esta otra (forma humana de pensar lógica) no funcionará (no importa si se usa para bucle, bucle de tiempo, repita hasta, 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
Eso es lo que he probado por mi cuenta en Turbo Delphi 2006.
Hice un EnumerationEnumerator para que pudieras usarlo en la declaración ''for ... in'' en Delphi. Sin embargo, en ese entonces a veces generaría errores internos del compilador.
Editar:
Se las arregló para que funcione en Delphi 2007 en adelante, vea este artículo del blog (y la discusión bastante interesante debajo de él).
Puede usar Succ (x) y Pred (x) para recorrer una enumeración. ¡Pero recuerde verificar los límites para no probar Succ (x) en el último elemento de la enumeración!
Ejemplo:
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;
Sencillo:
type
TWeekdays = (wdMonday, wdTuesday, wdWednesday, wdThursday, wdFriday);
procedure Test;
var
el: TWeekdays;
begin
for el := Low(TWeekdays) to High(TWeekdays) do
; //
end;