问题
I am using Delphi 6 Professional. I am interfacing with a DLL libraty that declares an enumberated type as follows:
TExtDllEnum = (ENUM1 = $0, ENUM2 = $1, ENUM3 = $2, ENUM4 = $4, ENUM5 = $8, ENUM6 = $10);
As you can see the initialized values are not contiguous. If I try to iterate the type using a for loop as follows:
var
e: TExtDllEnum;
begin
for e := Low(TExtToDllEnum) to High(TExtToDllEnum) do
... // More code
end;
Delphi still increments e by 1 each loop invocation and thereby creates numeric values for e that are not members of the enumerated type (for example, '3'), and resulting in an 'out of bounds' error. How can I iterate the enumerated type in a for loop that generates only valid values for the enumerated type?
Thanks.
回答1:
By defining a set of constants...
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.
and implemented as an iterator - just for fun...
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.
回答2:
As far as I can remember, there's no way to iterate the way you want. If the enumeration is not changed frequently, a workaround may be to declare a "index array", which let you iterate the way you want. The trick is you don't iterate over the enumeration, but over a index which you can in turn "convert" to a valid element in the enum:
I think I can explain the idea better in code:
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:
When you define the enumeration
TExtDllEnum = (ENUM1 = $0, ENUM2 = $1, ENUM3 = $2, ENUM4 = $4, ENUM5 = $8, ENUM6 = $10);
you actually define the enumeration type consisting of 17 ($10 + 1) possible values. That is documented.
There are a lot of ways to implement the iteration over assigned enumeration constants only (see the other answers), but the way you are doing it you iterate over 17 values, and that cannot be changed.
Here is one more iteration example that uses the fact that all ENUMx values except ENUM1 are powers of 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;
回答4:
You can't
if the values are binary weighted try using a while loop like this
var
e: TExtDllEnum;
begin
e := 0;
While e <= High(TExtToDllEnum) do
begin
... // More code
e := Power(2, e);
end;
end;
来源:https://stackoverflow.com/questions/3817565/how-to-iterate-initialized-enumerated-types-with-delphi-6-and-avoid-the-out-of