在Delphi中循环遍历不规则枚举

7

1)有人知道在Delphi(XE)中是否可以循环遍历不规则枚举吗?

遍历正常枚举是可以的。来自Delphi Basics

var
  suit : (Hearts, Clubs, Diamonds, Spades);
begin
// Loop 3 times
For suit := Hearts to Diamonds do
   ShowMessage('Suit = '+IntToStr(Ord(suit)));
end;

但是,如果将“suit”声明为
var
  suit : (Hearts=1, Clubs, Diamonds=10, Spades);

它循环10次。这并不令人惊讶,但我想循环3次。到目前为止,我找到的唯一解决方案是将枚举转换为集合,并像delphi.about.com上那样使用“for ... in”循环。

因此,如果问题1)的答案是否定的,则:
2)如何在Delphi中从枚举转换为集合?

我在一个编辑框(TEdit)组件数组中使用它,该数组具有不规则编号(edit1、edit5、edit7、edit3等)。虽然可以重新排序所有编辑框,但这会删除使用枚举作为灵活方式允许在枚举中间添加编辑框的原因。


为什么不能使用一些TList的后代并迭代它们? - Ignacio Vazquez-Abrams
枚举将用作TLabels、TEdits和Strings数组中的索引,以便我可以使用StringArray [Job]:= Editbox [Job]。TList可能有效,但目标是通过使用(不规则的)枚举作为索引使源代码更易于阅读 - 就像Java中的HashMap一样。我现在看到这可能行不通... - Truls
你尝试过使用 XE 的 RTTI 吗?从 TypInfo 单元中获取的普通 RTTI 表现非常糟糕。显然,您无法在不规则枚举上获取 TypeInfo(),我也尝试了使用集合,但结果只给了我访问冲突。 - Jens Mühlenhoff
我最近才开始使用Delphi XE(和Delphi),并没有深入研究RTTI。只是用它将枚举转换为字符串:GetEnumName(TypeInfo(TparameterList)),但那只是一个普通的枚举。 - Truls
1
太棒了!顺便说一下,Stackoverflow在帮助开发人员解决问题方面的工作方式让人印象深刻。今天发布了问题,今天就解决了 :) - Truls
6个回答

7

我现在手头没有Delphi编译器,但我认为Gabr的方法可以通过以下方式显著改进:

type
  TSuit = (Hearts = 1, Clubs, Diamonds = 10, Spades);

const
  Suits: array[0..3] of TSuit = (Hearts, Clubs, Diamonds, Spades);

谁知道呢,也许它甚至不能编译。


1
已测试过,它可以正常工作!谢谢。如果有人知道是否有可能避免重复枚举列表,我会很高兴知道。 - Truls

3
type
  TSuit = (Hearts=1, Clubs, Diamonds=10, Spades);

var
  suit: TSuit;
  suitEnum: array [1..4] of TSuit;

//initialization
suitEnum[1] := Hearts;
suitEnum[2] := Clubs;
suitEnum[3] := Diamonds;
suitEnum[4] := Spades;

for suit in suitEnum do
  DoSomething(suit);

谢谢您的建议。由于我的枚举中有大约30个元素,我希望避免手动初始化。但如果没有捷径,我会尝试手动初始化。 - Truls

2

我经常使用

var
  s: TSuit;
begin
  for s := Low(TSuit) to High(TSuit) do
    {something};
end;

3
如果枚举是规律的,即连续的数字,那么这个方法效果很好,但是关键在于这里的枚举是非连续的 - Truls

0

一种简单选项,对于小枚举非常有用:

type
  TSuit = (Hearts = 1, Clubs, Diamonds = 10, Spades);
var
  Suit: TSuit;
begin
  for Suit in [Hearts, Clubs, Diamonds] do
    WriteLn(Ord(Suit));

在 Delphi 2007 中工作得很好。不确定旧版本是否可用。请注意,使用for Suit in [Hearts..Diamonds] do也有与您的循环相同的问题。
顺便说一下,我使用 WriteLn() 因为我将此测试在控制台应用程序中。 :-)


谢谢你的建议,我会记住的。然而,由于这个案例有大约30个元素,我将使用被接受答案中建议的const方法。 - Truls
即使有30个元素,您仍应该能够从其原始声明中复制/粘贴范围,并将集合分配给某个常量,以便在所有循环中重复使用。它还有一个额外的好处:您可以跳过起始和结束元素之间的元素。 - Wim ten Brink

0

使用 Ord(Hearts) 到 Ord(Spades) 进行循环吗?


4
我认为从红桃到黑桃的Ord值会循环11次,而不是我想要的3次。 - Truls

0
应该明白(但通常不是)一旦你将硬序数分配放入枚举中,它就不再是帕斯卡式枚举类型 - 它只成为一个“常量包”,这并不相同。这就是C程序员所称的枚举。然而,帕斯卡式枚举类型在所有标准上都是有序的:它具有离散连续的值,对基本操作ORD、PRED、SUCC有有意义的响应。C中的枚举不会这样做,一旦你强制将序数分开,帕斯卡中的枚举也不会这样做。
这就是Delphi的RTTI拒绝返回类型信息的原因。实际上,对于所有目的而言,该类型基本上是tkUnknown,并且必须被视为编译时常量的“包”。仅仅因为它仍然口头上表示为有序,并且(有时摇摇欲坠地)支持在集合中使用,人们才会认为它应该像一个真正的枚举类型一样运作。最好理解它的真实含义:向C中的枚举值致敬。避免混合编码隐喻!
如果你这样做,那么你的解决方案就变得很明显:使用一个枚举类型(一个适当的枚举类型)来索引相应的常量数组。然后,你可以将序数设置为任何你想要的值,并且枚举类型保留其完整的RTTI定义作为适当的枚举类型。因此:你的枚举类型包含适当的不变序数值。通过使用枚举类型索引常量数组,你可以获得有趣的数字 - 因此,数组[MyEnums] of byte = (1,3,8,22,99,whatever)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接