2010-09-28 13 views
7

Estoy usando Delphi 6 Professional. Estoy de interfaz con un Libraty DLL que declara un tipo enumberated de la siguiente manera:¿Cómo se iteran los tipos enumerados inicializados con Delphi 6 y se evita el error "fuera de límites"?

TExtDllEnum = (ENUM1 = $0, ENUM2 = $1, ENUM3 = $2, ENUM4 = $4, ENUM5 = $8, ENUM6 = $10); 

Como se puede ver los valores inicializados no son contiguas. Si intento para iterar el tipo utilizando un bucle como sigue:

var 
    e: TExtDllEnum; 
begin 
    for e := Low(TExtToDllEnum) to High(TExtToDllEnum) do 
    ... // More code 
end; 

Delphi todavía incrementos e por 1 cada invocación de bucle y de este modo crea valores numéricos para e que no son miembros de la tipo enumerado (por ejemplo, ' 3 '), y que da como resultado un error' fuera de límites '. ¿Cómo puedo iterar el tipo enumerado en un ciclo for que solo genera valores válidos para el tipo enumerado?

Gracias.

Respuesta

13

Mediante la definición de un conjunto de constantes ...

type 
    TExtDllEnum = (ENUM1 = $0, ENUM2 = $1, ENUM3 = $2, ENUM4 = $4, ENUM5 = $8, ENUM6 = $10); 

const 
    CExtDllEnumSet = [ENUM1, ENUM2, ENUM3, ENUM4, ENUM5, ENUM6]; 


var 
    e: TExtDllEnum; 
begin 
    e := Low(TExtDllEnum); 
    while e <= High(TExtDllEnum) do 
    begin 
    if e in CExtDllEnumSet then 
     WriteLn(Ord(e)); 

    Inc(e); 
    end; 

    ReadLn; 
end. 

e implementado como un iterador - solo por diversión ...

type 
    TExtDllEnum = (ENUM1 = $0, ENUM2 = $1, ENUM3 = $2, ENUM4 = $4, ENUM5 = $8, ENUM6 = $10); 
const 
    CExtDllEnumSet = [ENUM1, ENUM2, ENUM3, ENUM4, ENUM5, ENUM6]; 

type 
    TMyIterator = class 
    private 
    FValue: TExtDllEnum; 
    public 
    constructor Create; 
    function Next: TExtDllEnum; 
    function HasNext: Boolean; 
    end; 

    constructor TMyIterator.Create; 
    begin 
    FValue := Low(TExtDllEnum); 
    end; 

    function TMyIterator.HasNext: Boolean; 
    begin 
    Result := FValue <= High(TExtDllEnum); 
    end; 

    function TMyIterator.Next: TExtDllEnum; 
    begin 
    Result := FValue; 

    repeat 
     Inc(FValue); 
    until (FValue in CExtDllEnumSet) or (FValue > High(TExtDllEnum)) 
    end; 

var 
    MyIterator: TMyIterator; 
begin 
    MyIterator := TMyIterator.Create; 

    while MyIterator.HasNext do 
    WriteLn(Ord(MyIterator.Next)); 

    MyIterator.Free; 

    ReadLn; 
end. 
7

Por lo que puedo recordar, no hay forma de repetir la forma que desee. Si la enumeración no se cambia con frecuencia, una solución alternativa puede ser declarar una "matriz de índices", que le permite iterar de la manera que desee. El truco es que no es iterar sobre la enumeración, pero en un índice que puede a su vez "convertir" a un elemento válido en la enumeración:

creo que puedo explicar mejor la idea de código:

const 
    ExtDllEnumElements = 6; 
    EnumIndexArray: array[0..ExtDllEnumElements - 1] of TExtDllEnum = (ENUM1, ENUM2, ENUM3, ENUM4, ENUM5, ENUM6); 
var 
    I: Integer; 
begin 
    for I := Low(EnumIndexArray) to High(EnumIndexArray) do 
    WhateverYouWantWith(EnumIndexArray[I]); 
end; 
3

no se puede

si los valores son intento ponderada binaria usando un bucle while como esto

var 
    e: TExtDllEnum; 
begin 
    e := 0; 
    While e <= High(TExtToDllEnum) do 
    begin 
     ... // More code 
     e := Power(2, e); 
    end; 

end; 
4

Cuando se define la enumeración

TExtDllEnum = (ENUM1 = $0, ENUM2 = $1, ENUM3 = $2, ENUM4 = $4, ENUM5 = $8, ENUM6 = $10); 

realmente define el tipo de enumeración que consta de 17 ($ 10 + 1) valores posibles. Eso es documented.

Hay muchas maneras de implementar la iteración sobre las constantes de enumeración asignadas solamente (ver las otras respuestas), pero la forma en que lo hace itera sobre 17 valores, y eso no se puede cambiar.

Aquí es un ejemplo más de iteración que utiliza el hecho de que todos los valores excepto ENUMx Enum1 son potencias de 2:

type 
    TExtDllEnum = (ENUM1 = $0, ENUM2 = $1, ENUM3 = $2, 
       ENUM4 = $4, ENUM5 = $8, ENUM6 = $10); 
var 
    e: TExtDllEnum; 

begin 
    e:= Low(TExtDllEnum); 
    repeat 
    [..] 
    if e = ENUM1 then e:= ENUM2 
    else if e = High(TExtDllEnum) then Break 
    else e:= e shl 1; 
    until False; 
end; 
Cuestiones relacionadas