Как повторить инициализированные перечисленные типы с Delphi 6 и избегайте ошибки «вне границ»?
Вопрос
Я использую Delphi 6 Professional. Я взаимодействую с DLL Libraty, которая объявляет девверованный тип следующим образом:
TExtDllEnum = (ENUM1 = $0, ENUM2 = $1, ENUM3 = $2, ENUM4 = $4, ENUM5 = $8, ENUM6 = $10);
Как вы можете видеть, инициализированные значения не являются смежными. Если я стараюсь повторять тип, используя A для цикла следующим образом:
var
e: TExtDllEnum;
begin
for e := Low(TExtToDllEnum) to High(TExtToDllEnum) do
... // More code
end;
Delphi все еще увеличивается на 1 каждую вызов цикла и тем самым создает числовые значения для E, которые не являются членами перечисленного типа (например, «3»), а также приводят к ошибке «вне оценки». Как я могу перечислить перечисленный тип в цикле для цикла, который генерирует только допустимые значения для перечисленного типа?
Спасибо.
Решение
Определив набор констант ...
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.
И реализован как итератор - просто для удовольствия ...
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.
Другие советы
Насколько я могу вспомнить, нет никакого способа потерять то, как вы хотите. Если перечисление не изменяется часто, обходной путь может заключаться в том, чтобы объявить «индексный массив», который позволит вам повторить, как вы хотите. Хитрость - это вы не повторяете перечисление, но по индексу, который вы можете в свою очередь, «преобразовать» на действительный элемент в Enum:
Я думаю, что могу объяснить идею лучше в коде:
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;
Когда вы определяете перечисление
TExtDllEnum = (ENUM1 = $0, ENUM2 = $1, ENUM3 = $2, ENUM4 = $4, ENUM5 = $8, ENUM6 = $10);
Вы на самом деле определяете тип перечисления, состоящий из 17 (10 + 1) возможных значений. То есть документированный.
Есть много способов реализации итерации по сравнению с назначенными константами перечисления (см. Другие ответы), но как вы делаете это, вы используете его, вы выполняете его, вы выполняете более 17 значений, и это нельзя изменить.
Вот еще один пример итерации, который использует тот факт, что все значения Enumx, кроме Enum1, являются полномочиями 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;
Вы не можете
Если значения являются бинарными взвешенными, попробуйте использовать цикл A, как это
var
e: TExtDllEnum;
begin
e := 0;
While e <= High(TExtToDllEnum) do
begin
... // More code
e := Power(2, e);
end;
end;