2009-10-21 39 views
16

Quiero repetir los elementos en una enumeración.Iterar a través de elementos en una enumeración en Delphi

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 llegar es la siguiente:

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 como esto:

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; 

que funciona bien, excepto la lista consigo es similar al siguiente (observe los dos últimos puntos):

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 manera mejor de iterar a través de los elementos de un tipo enumerado?

Si no es así, es seguro asumir que habrá siempre ser exactamente dos artículos adicionales usando mi método actual? Obviamente, uno es el nombre de la Unidad ... pero, ¿qué está haciendo el símbolo "@"? ¿Es realmente basura, o es más información tipo?

Estoy usando Delphi 2007. Gracias por cualquier idea.

Respuesta

51

simple:

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

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

Ok, soy un idiota. Intenté esto antes, pero dejé mi "el" como un número entero y no me di cuenta de mi error. Gracias. – JosephStyons

+0

Aún me pregunto qué significa "@". – JosephStyons

+3

MaxEnum probablemente tiene errores; devolviendo más que el recuento real de enumeraciones. Y GetEnumName usa ese resultado erróneo para analizar las estructuras internas en su código. Lo que obtienes son trozos de memoria al azar más allá de las estructuras internas. –

0

me hizo una EnumerationEnumerator por lo que podría utilizarlo en el 'para ... en la declaración en Delphi. Sin embargo, en ese momento a veces generaba errores internos del compilador.

Editar:

arreglamos para conseguir que funcione en Delphi 2007 y hasta, ver this blog article (y la discusión bastante interesante debajo de ella).

+3

¡Interesante! Nunca entendí por qué eso no es posible en primer lugar. – Giel

+0

@Giel: aquí está http://wiert.wordpress.com/2009/10/27/delphi-for-in-on-enumerated-data-types/ –

4

Es bastante más complejo que eso, cuando se utiliza enumeraciones especiales ... vamos a ver una solución realmente 100% que trabaja para una definición enumerado complejo:

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 todos
  • 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.)
  • ver cómo se ha añadido una matriz constante con el orden correcto de los elementos
  • Debe iterar sobre dicha matriz puesto que el orden se pierde y Suc y Pred no funcionan correctamente en ese tipo de enumeraciones

¿Por qué ha sido hecho así?:

  • orden enumerado debe ser conservada y no es contigua
  • Delphi cuando en ese ejemplo crea escriba TmyEnumType asignar a la misma (9-2 + 1 = 8) elemments (de uno inferior (2) a una mayor uno (9), por lo que los valores válidos para dicho tipo van del ordinal 2 al ordinal 9
  • Las funciones Delphi Succ y Pred solo aumentan y disminuyen en uno, no verifican la forma no contigua de definirlo, así que asigne valores que son fuera del alcance, y también perder el orden de la definición

El truco :

  • declarar una matriz constante contigua con elementos en el orden correcto
  • bucle en esa matriz constante

Si intenta este otro (modo humano lógica de pensamiento) no va a funcionar (sin importa si uso bucle for, while, repita hasta 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 

Eso es lo que he probado por mi propia en Turbo Delphi 2006.

+1

¿Por qué las personas siguen disparándose en el pie con non ¿Enumeraciones contiguas? –

3

Puede usar Succ (x) y Pred (x) para recorrer una enumeración. ¡Pero recuerde verificar los límites para que no pruebe 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; 
Cuestiones relacionadas