Loop through irregular enumeration in Delphi

2019-02-17 06:20发布

1) Does anyone know if it is possible to loop through an irregular enumeration in Delphi (XE)?

Looping over a normal enumeration is ok. From Delphi Basics:

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

But, if 'suit' instead is declared as

var
  suit : (Hearts=1, Clubs, Diamonds=10, Spades);

it loops 10 times. Not suprising, but I would like to loop 3. The only solution I've found so far is converting an enumeration to a set and use the 'for ... in'-loop like on delphi.about.com.

So, if answer to question 1) is no, then:
2) How to convert from enumeration to set in Delphi?

The context I am using it in is a component array of edit-boxes (TEdit) that has an irregular numbering (edit1, edit5, edit7, edit3, ...). While it is possible to reorder all the edit-boxes, it removes the reason of using enumeration as a flexible way to allow addition of an edit-box in the middle of the enumeration.

6条回答
可以哭但决不认输i
2楼-- · 2019-02-17 06:57

A dirty option, useful for small enumerations:

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

Works nice in Delphi 2007. Don't know about older versions. Be aware, using for Suit in [Hearts..Diamonds] do has the same problem as your loop.
Btw, I use WriteLn() because I tested this in a console application. :-)

查看更多
老娘就宠你
3楼-- · 2019-02-17 06:58

I do not have a Delphi compiler at hand right now, but I tink that gabr's approach can be rather significantly improved by doing

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

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

Who knows, maybe it doesn't even compile.

查看更多
Ridiculous、
4楼-- · 2019-02-17 07:03

Loop using Ord(Hearts) to Ord(Spades) ?

查看更多
我欲成王,谁敢阻挡
5楼-- · 2019-02-17 07:07

I always use

var
  s: TSuit;
begin
  for s := Low(TSuit) to High(TSuit) do
    {something};
end;
查看更多
我欲成王,谁敢阻挡
6楼-- · 2019-02-17 07:08
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);
查看更多
Summer. ? 凉城
7楼-- · 2019-02-17 07:08

It should be understood (and often isn't) that the moment you put hard ordinal assignments into an enumeration, it ceases for all intents to be a Pascalian enumerated type - it just becomes a "bag of constants", which is not the same thing. This is what C-programmers call enumerations. However, a Pascalian enumerated type is ORDINAL in all criterion: It has discrete consecutive values that respond meaningfully to the base operations ORD, PRED, SUCC. Enumerations in C don't do this, and neither do enums in Pascal once you force the ordinals apart.

THIS is the reason that Delphi's RTTI basically refuses to return type information once this has been done. To all intents the type is essentially a tkUnknown, and has to be treated as a 'bag' of compile-time constants. It is only because it still plays lip service to being an ordinal and has (sometimes shaky) support for use in sets that people are led into believing it should still behave like a proper enumerated type. It's better to just understand it for what it really is: a nod to enumerated values in C. Avoid mixing the coding metaphor!

If you do this, then your solution becomes obvious: you use an enumerated type (a proper one) to index a corresponding array of CONSTANTS. Then you can make the ordinals whatever you want, and the enums retain their full RTTI definitions as a proper enumeration. So: your ENUMERATED TYPE contains proper unchanged ordinal values. You get your funny numbers by indexing the constants array using the enumeration -ergo array [MyEnums] of byte = (1,3,8,22,99,whatever)

查看更多
登录 后发表回答