如何使用 Delphi 6 迭代初始化的枚举类型并避免“越界”错误?
Posted
技术标签:
【中文标题】如何使用 Delphi 6 迭代初始化的枚举类型并避免“越界”错误?【英文标题】:How to iterate initialized enumerated types with Delphi 6 and avoid the "out of bounds" error? 【发布时间】:2011-04-18 13:39:49 【问题描述】:我正在使用 Delphi 6 Professional。我正在与一个声明数字类型的 DLL 库接口,如下所示:
TExtDllEnum = (ENUM1 = $0, ENUM2 = $1, ENUM3 = $2, ENUM4 = $4, ENUM5 = $8, ENUM6 = $10);
如您所见,初始化值不是连续的。如果我尝试使用 for 循环迭代类型,如下所示:
var
e: TExtDllEnum;
begin
for e := Low(TExtToDllEnum) to High(TExtToDllEnum) do
... // More code
end;
Delphi 仍然在每次循环调用时将 e 递增 1,从而为 e 创建不是枚举类型成员的数值(例如,'3'),并导致“超出范围”错误。如何在只为枚举类型生成有效值的 for 循环中迭代枚举类型?
谢谢。
【问题讨论】:
【参考方案1】:通过定义一组常量...
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.
【讨论】:
【参考方案2】:据我所知,没有办法以您想要的方式进行迭代。如果枚举不经常更改,解决方法可能是声明一个“索引数组”,它可以让您以您想要的方式进行迭代。诀窍是您不要遍历枚举,而是遍历一个索引,然后您可以将其“转换”为枚举中的有效元素:
我想我可以用代码更好地解释这个想法:
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】:定义枚举时
TExtDllEnum = (ENUM1 = $0, ENUM2 = $1, ENUM3 = $2, ENUM4 = $4, ENUM5 = $8, ENUM6 = $10);
您实际上定义了由 17 ($10 + 1) 个可能值组成的枚举类型。 那是documented。
有很多方法可以仅在分配的枚举常量上实现迭代(请参阅其他答案),但是您这样做的方式是迭代 17 个值,并且无法更改。
这是另一个迭代示例,它使用了除 ENUM1 之外的所有 ENUMx 值都是 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】:你不能
如果值是二进制加权的,请尝试使用这样的 while 循环
var
e: TExtDllEnum;
begin
e := 0;
While e <= High(TExtToDllEnum) do
begin
... // More code
e := Power(2, e);
end;
end;
【讨论】:
以上是关于如何使用 Delphi 6 迭代初始化的枚举类型并避免“越界”错误?的主要内容,如果未能解决你的问题,请参考以下文章