Delphi 未为固定枚举返回RTTI属性:这是错误吗?

Delphi 未为固定枚举返回RTTI属性:这是错误吗?,delphi,rtti,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:

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

见下例:

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(使用GetPropInfo):除了上述类型的属性之外,所有属性都可以找到

所有班级都有同样的表现。我还复制了一个样本项目

在使用和不使用各种RTTI指令的情况下进行了尝试,没有任何更改

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

使用Delphi2010 Ent+Update5

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

谢谢,巴里·凯利:

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

我曾考虑为Delphi 2010实现TKDisContentiguousEnumeration(或者可能更好地命名为member),但考虑到它们的相对稀缺性和枚举中的困难,好处似乎很小-如何有效地对范围进行编码?有些编码对某些场景更好,对其他场景更差


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

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

例如:

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语言指南》中的枚举类型部分找到。

这是一个限制。具有显式序数的枚举类型不能具有RTTI。记录在案

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

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

实际的枚举往往占据连续的范围,因此您可能不会得到数以百万计的保留值。若要与C样式的位字段进行互操作,则必须将值拆分为不同的枚举和集合

谢谢你的及时答复。因此,对于我的问题,最后还有一个简单的解决方法:让枚举显式值从0开始,而不是从1开始。我确信用RTTI检测枚举是一种非常繁重的方法(对调试构建非常有用,tho)。这里的目标是在没有硬编码方法的情况下序列化和取消序列化对象,对于一个自定义ORM。为什么没有任何评论就被否决了+1因为我觉得这个答案很有用。它很好地展示了如何解决这个问题。