在 Delphi 中迭代枚举中的项目

发布于 2024-08-08 15:54:47 字数 1379 浏览 3 评论 0原文

我想迭代枚举中的项目。

我希望能够这样说:

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;

我能得到的最接近的是:

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;

我这样使用:

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;

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

wdMonday
wdTuesday
wdWednesday
wdThursday
wdFriday
Unit1
'@'#0'ôÑE'#0#0#0#0#0#0#0#0#0#0#0#0#0  <more garbage characters>

最后的两条显然不是我想要的。

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

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

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

I want to iterate through the items in an enumeration.

I'd like to be able to say something like this:

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;

The closest I've been able to come is this:

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;

Which I use like this:

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;

That works well, except the list I get looks like this (notice the last two items):

wdMonday
wdTuesday
wdWednesday
wdThursday
wdFriday
Unit1
'@'#0'ôÑE'#0#0#0#0#0#0#0#0#0#0#0#0#0  <more garbage characters>

The two items at the end are obviously not what I want.

Is there a better way to iterate through the elements of an enumerated type?

If not, then is it safe to assume that there will always be exactly two extra items using my current method? Obviously one is the Unit name... but what is the "@" symbol doing? Is it really garbage, or is it more type information?

I'm using Delphi 2007.
Thanks for any insights.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

甜柠檬 2024-08-15 15:54:47

简单的:

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

procedure Test;
var
  el: TWeekdays;
begin
  for el := Low(TWeekdays) to High(TWeekdays) do
    ; //
end;

Simple:

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

procedure Test;
var
  el: TWeekdays;
begin
  for el := Low(TWeekdays) to High(TWeekdays) do
    ; //
end;
你的心境我的脸 2024-08-15 15:54:47

当使用特殊枚举时,它比这要复杂得多......让我们看看复杂枚举定义的真正 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

注意:

  • 并非所有枚举定义都必须以 0 开头并且是连续的,可以按照示例进行定义
  • 查看类型是如何定义的(未排序、不连续等...)
  • 查看如何添加具有正确元素顺序的常量数组
  • 必须迭代此类数组,因为顺序会丢失,而 Succ 和 Pred 不会丢失在这种枚举上可以正常工作

为什么这样做?:

  • 枚举顺序必须保守,并且在该示例上创建类型 TmyEnumType 分配给它时,它不是连续的
  • Delphi (9-2+1 =8) 元素(从低一 (2) 到高一 (9),因此此类类型的有效值为从序数 2 到序数 9
  • Delphi Succ 和 Pred 函数仅增加和减少 1,不检查非连续定义它的方法,因此分配超出范围的值,并且还会失去定义的顺序

技巧:

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

如果您尝试其他(逻辑人类方式)思考)它不会工作(无论是否使用for循环,while循环,重复直到等):

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

这是我自己在Turbo Delphi 2006上测试过的。

It is quite more complex than that, when used special enumerations... let's see a really 100% working solution for a complex enumerated definition:

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

Notes:

  • Not all enumerated definitions must start with 0 and be contiguous, can be defined as on the sample
  • See how the type has been defined (not sorted, not contiguous, etc...)
  • See how it has been added a constant array with the correct order of the elements
  • Must iterate on such array since order is lost and Succ and Pred do not work properly on that kind of enumerations

Why it has been done like that?:

  • Enumerated order must be conserved and it is not contiguous
  • Delphi when on that sample creates type TmyEnumType assign to it (9-2+1=8) elemments (from lower one (2) to higher one (9), so valid values for such type are from ordinal 2 to ordinal 9
  • Delphi Succ and Pred functions only increase and decrese by one, do not check for non-contiguous way of defining it, so assign values that are out of scope, and also loose the order of definition

The Trick:

  • Declare a contiguous constant array with elements in the correct order
  • Loop on that constant array

If you try this other (logical human way of thinking) it will not work (no matter if use for loop, while loop, repeat until, etc):

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

That is what i have tested by my own on Turbo Delphi 2006.

听风吹 2024-08-15 15:54:47

您可以使用 Succ(x) 和 Pred(x) 循环遍历枚举。但请记住检查边界,这样您就不会在枚举中的最后一个元素上尝试 Succ(x)!

例子:

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

procedure Test;
var
  val: TWeekdays;
begin
  val := wdTuesday;
  val := Succ(val); // wdWednesday

  val := wdFriday;
  val := Pred(val); // wdThursday, 
end;

You can use Succ(x) and Pred(x) to loop through an enumeration. But remember to check for boundaries so you don't try Succ(x) on the last element in the enumeration!

Example:

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

procedure Test;
var
  val: TWeekdays;
begin
  val := wdTuesday;
  val := Succ(val); // wdWednesday

  val := wdFriday;
  val := Pred(val); // wdThursday, 
end;
苏璃陌 2024-08-15 15:54:47

我制作了一个 EnumerationEnumerator,以便您可以在 Delphi 的“for ... in”语句中使用它。
然而,当时它有时会产生内部编译器错误。

编辑:

设法让它在Delphi 2007及更高版本中工作,请参阅这篇博客文章(及其下非常有趣的讨论)。

I made an EnumerationEnumerator so you could use it in the 'for ... in' statement in Delphi.
However, back then it would sometimes generate internal compiler errors.

Edit:

Managed to get it to work in Delphi 2007 and up, see this blog article (and the quite interesting discussion under it).

云雾 2024-08-15 15:54:47

此示例在 Delphi Sydney (10.4)

 type
   TDay = (Mon=1, Tue, Wed, Thu, Fri, Sat, Sun);   // Enumeration values
 var
   day   : TDay;          // Enumeration variable
 begin
   for day := Mon to Fri do
      Caption:= IntToStr(ord(day));
 end;

(http://www.delphibasics. co.uk/Article.asp?Name=Sets

This example compiles on Delphi Sydney (10.4)

 type
   TDay = (Mon=1, Tue, Wed, Thu, Fri, Sat, Sun);   // Enumeration values
 var
   day   : TDay;          // Enumeration variable
 begin
   for day := Mon to Fri do
      Caption:= IntToStr(ord(day));
 end;

( http://www.delphibasics.co.uk/Article.asp?Name=Sets )

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文