在Delphi中迭代枚举中的项目

Jos*_*ons 21 delphi enums

我想迭代枚举中的项目.

我希望能够说出这样的话:

type
  TWeekdays = (wdMonday, wdTuesday, wdWednesday, wdThursday, wdFriday);

...
elementCount := GetElementCount(TypeInfo(TWeekDays));

for i := 0 to elementCount - 1 do begin
  ShowMessage(GetEnumName(TypeInfo(TWeekdays),i));
end;
Run Code Online (Sandbox Code Playgroud)

我能来的最接近的是:

function MaxEnum(EnumInfo: PTypeInfo): integer;
const
  c_MaxInt = 9999999;
var
  i: integer;
  s: string;
begin
  //get # of enum elements by looping thru the names
  //until we get to the end.
  for i := 0 to c_MaxInt do begin
    s := Trim(GetEnumName(EnumInfo,i));
    if 0 = Length(s) then begin
      Result := i-1;
      Break;
    end;
  end;
end;
Run Code Online (Sandbox Code Playgroud)

我用的是这样的:

procedure TForm1.BitBtn1Click(Sender: TObject);
var
  i, nMax: integer;
begin
  ListBox1.Clear;
  nMax := MaxEnum(TypeInfo(TWeekdays));
  for i := 0 to nMax do begin
    ListBox1.Items.Add(GetEnumName(TypeInfo(TWeekdays),i));
  end;
end;
Run Code Online (Sandbox Code Playgroud)

这很好,除了我得到的列表看起来像这样(注意最后两项):

wdMonday
wdTuesday
wdWednesday
wdThursday
wdFriday
Unit1
'@'#0'ôÑE'#0#0#0#0#0#0#0#0#0#0#0#0#0  <more garbage characters>
Run Code Online (Sandbox Code Playgroud)

最后的两个项目显然不是我想要的.

有没有更好的方法来迭代枚举类型的元素?

如果没有,那么可以安全地假设使用我当前的方法总会两个额外的项目吗?显然一个是单位名称......但是"@"符号在做什么?它真的是垃圾,还是更多的类型信息?

我正在使用Delphi 2007.感谢您的任何见解.

gab*_*abr 59

简单:

type
  TWeekdays = (wdMonday, wdTuesday, wdWednesday, wdThursday, wdFriday);

procedure Test;
var
  el: TWeekdays;
begin
  for el := Low(TWeekdays) to High(TWeekdays) do
    ; //
end;
Run Code Online (Sandbox Code Playgroud)

  • 好吧,我是个白痴.我之前尝试过这个,但是我将"el"作为整数留下了,并没有意识到我的错误.谢谢. (5认同)
  • GetEnumName信任您传递的是有效值.它首先读取TTypeData.NameList字段,然后是EnumUnitName字段.之后是垃圾:函数解释为字符串长度的一个字节值,加​​上函数认为的字符串内容.你很幸运,你只有两个额外的字符串.要确定PTypeInfo的最大枚举值,请阅读MaxValue字段:`GetTypeData(TypeInfo(TWeekdays)).MaxValue`.该字段适用于所有序数类型. (4认同)
  • MaxEnum可能是马车; 返回超过枚举的实际数量.并且GetEnumName使用该错误结果来分析代码中的内部结构.你得到的是内部结构之后的随机内存. (3认同)

小智 6

当使用特殊枚举时,它比这复杂得多......让我们看一个复杂的枚举定义真正100%工作的解决方案:

type
    TmyEnumType=(myEnumTypeA=5,myEnumTypeB=2,myEnumTypeC=9);
const
     myEnumTypeOrder:Array[1..3] of TmyEnumType=(myEnumTypeA,myEnumTypeB,myEnumTypeC);
procedure TForm1.Button1Click(Sender: TObject);
var
   myEnumTypeVariable:TmyEnumType;
begin
     myEnumTypeVariable:=Low(TmyEnumType);
     for myEnumTypeVariable in myEnumTypeOrder
     do begin
             ShowMessage(IntToStr(Ord(myEnumTypeVariable))); // Sample code to show enum integer value
             // Extra code you neede
        end;
end;
// This code shows three messages in this secuence: 5, 2, 9
//    Correct number of elements and in the correct order
Run Code Online (Sandbox Code Playgroud)

笔记:

  • 并非所有枚举定义都必须以0开头并且是连续的,可以在样本上定义
  • 了解如何定义类型(未排序,不连续等)...
  • 了解如何使用正确的元素顺序添加常量数组
  • 必须迭代这样的数组,因为订单丢失,Succ和Pred在这种枚举上不能正常工作

为什么这样做?:

  • 枚举的顺序必须是守恒的,并且不是连续的
  • 德尔福在该样本上创建类型TmyEnumType赋值(9-2 + 1 = 8)元素(从较低的一(2)到较高的一(9)),因此这种类型的有效值从序数2到序数9
  • Delphi Succ和Pred函数只增加和减少一个,不检查定义它的非连续方式,因此分配超出范围的值,并且也松开定义的顺序

诀窍:

  • 使用正确顺序的元素声明一个连续的常量数组
  • 循环在该常量数组上

如果你尝试这个(逻辑的人类思维方式)它将无法工作(无论是使用循环,循环,重复,直到等):

type
    TmyEnumType=(myEnumTypeA=5,myEnumTypeB=2,myEnumTypeC=9);
procedure TForm1.Button1Click(Sender: TObject);
var
   myEnumTypeVariable:TmyEnumType;
begin
     for myEnumTypeVariable:=Low(TmyEnumType) to High(TmyEnumType);
     do begin
             ShowMessage(IntToStr(Ord(myEnumTypeVariable))); // Sample code to show enum integer value
             // Extra code you neede
        end;
end;
// This code shows eight messages in this secuence: 2, 3, 4, 5, 6, 7, 8, 9
//    Inorrect number of elements and in order is lost
Run Code Online (Sandbox Code Playgroud)

这就是我在Turbo Delphi 2006上测试过的.

  • 为什么人们继续用非连续的枚举射击自己? (2认同)