La forma de repetición inicializado tipos enumerados con Delphi 6 y evitar el error “fuera de límites”?
Pregunta
Estoy utilizando Delphi 6 Professional. Estoy de interfaz con un Libraty DLL que declara un tipo enumberated de la siguiente manera:
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 incrementa e por 1 cada invocación de bucle y de este modo crea valores numéricos para e que no son miembros del tipo enumerado (por ejemplo, '3'), y que resulta en un 'fuera de límites' error. ¿Cómo puedo iterar el tipo enumerado en un bucle for que genera solamente valores válidos para el tipo enumerado?
Gracias.
Solución
Al definir 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 - sólo 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.
Otros consejos
Por lo que yo puedo recordar, no hay manera de iterar la manera deseada. Si la enumeración no se cambia con frecuencia, una solución puede ser la de declarar una "matriz de índice", que le permiten iterar la manera deseada. El truco es no lo hace iterar sobre la enumeración, pero en un índice que se puede convertir en "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;
Cuando se define la enumeración
TExtDllEnum = (ENUM1 = $0, ENUM2 = $1, ENUM3 = $2, ENUM4 = $4, ENUM5 = $8, ENUM6 = $10);
que realmente definen el tipo de enumeración que consiste en 17 ($ 10 + 1) valores posibles. Es decir documentados .
Hay muchas formas de implementar la iteración más constantes de enumeración asignado solamente (ver las otras respuestas), pero la forma en que lo están haciendo iterar más de 17 valores, y que no se puede cambiar.
Aquí está una más iteración ejemplo 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;
No se puede
si los valores son try ponderado binario utilizando un tiempo de bucle como este
var
e: TExtDllEnum;
begin
e := 0;
While e <= High(TExtToDllEnum) do
begin
... // More code
e := Power(2, e);
end;
end;