delphi enums

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;