固定枚举不返回RTTI属性:它是一个错误吗?

时间:2011-10-22 07:00:19

标签: delphi rtti

我需要浏览某些类的所有已发布属性。 不列出类型为具有固定值的枚举的属性。

见下面的例子:

TMyEnum = (meBlue, meRed, meGreen);
TMyEnumWithVals = (mevBlue=1, mevRed=2, mevGreen=3);
TMyClass =
...
published
  property Color: TMyEnum read FColor write SetColor; // This one is found
  property ColorVal: TMyEnumWithVals read FColorVal write SetColorVal; // This one is never found
end;

我需要固定值,因为这些属性存储在数据库中,我需要确保分配的值始终相同,无论下一版本中的Delphi编译器选择如何,并防止在枚举列表中对未来值的任何错位插入

我尝试使用新的Delphi 2010 RTTI(带.GetDeclaredProperties)和“旧”RTTI(带GetPropInfos):除上述类型的属性外,找到所有属性。

在所有类中都可以看到相同的行为。我还在一个示例项目中复制了这个。

尝试使用和不使用各种RTTI指令而不做任何更改。

这是一个错误,一个已知的限制? 是否有解决方法(除了删除枚举的固定值)?

使用Delphi2010 Ent + Update5

[编辑]下面的答案提供了解决方法:枚举的第一个值必须设置为0而不是1,并且值是连续的。经过测试和运作的解决方案。

谢谢,

3 个答案:

答案 0 :(得分:6)

Barry Kelly says

  

不以零开头的不连续枚举和枚举没有typeinfo。对于要实现的typeinfo,由于向后兼容性问题,它需要采用与现有tkEnumeration不同的格式。

     

我考虑过为Delphi 2010实现一个tkDiscontiguousEnumeration(或者可能更好的命名成员),但考虑到它们的相对稀缺性和枚举的困难,它的好处似乎很小 - 你如何有效地编码范围?有些编码对某些情况更好,对其他情况则更糟。

所以这不是一个错误,而是一个已知的限制。

答案 1 :(得分:2)

这是一个限制。 具有显式常规的枚举类型不能具有RTTI。记录here

可能的解决方案是在枚举类型中声明Reserved值,例如:

TMyEnum = (meReserved1, meBlue, meRed, meGreen, meReserved2, meWhite); // and so on
...
Assert(MyEnum in [meBlue..meGreen, meWhite], 'sanity check failed')

实际的枚举往往会占据连续的范围,所以你最终可能不会宣布保留值。如果您要与C风格的位域互操作,则必须将值拆分为不同的枚举和集合。

答案 2 :(得分:1)

要添加更多背景信息,带有值的枚举将被视为具有预定义常量的子范围类型。

例如:

type
  TMyEnumWithVals = (mevBlue=1, mevRed=2, mevGreen=3);

被视为:

type
  TMyEnumWithVals = 1..3;
const 
  mevBlue  : TMyEnumWithVals = 1;
  mevRed   : TMyEnumWithVals = 2;
  mevGreen : TMyEnumWithVals = 3;

但是,如果不进行强制转换,则无法将这些与整数组合在一起。

var
  enum   : TMyEnumWithVals;
  ival   : Integer;
begin
  enum := mevBlue;
  ival := Integer(mevRed);

更糟糕的是,如果你使用:

type
  TTypeId  = (tidPrimary = 100, tidSecundary = 200, tidTertiary = 300);
  TTypeArray = array [TTypeID] of string;

你得到一个包含201个元素的数组,而不是3个元素。您可以使用以下值之间的值:

var
  enum   : TTypeId  ;
  ival   : Integer;
begin
  enum := TTypeId(150);  // Is valid.

此信息可在Delphi语言指南中找到,其中包含枚举类型部分。