我需要浏览某些类的所有已发布属性。 不列出类型为具有固定值的枚举的属性。
见下面的例子:
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,并且值是连续的。经过测试和运作的解决方案。
谢谢,
答案 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语言指南中找到,其中包含枚举类型部分。