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因为我觉得这个答案很有用。它很好地展示了如何解决这个问题。