为什么我用枚举类型得到“type has typeinfo”错误

时间:2009-09-14 09:40:33

标签: delphi enums rtti typeinfo

我已经声明了以下枚举类型,其中我希望第一个成员的序数值为1(一)而不是通常的0(零):

  type
    TMyEnum = (
               meFirstValue = 1,
               meSecondValue,
               meThirdValue
              );

如果我拨打 TypeInfo(),例如作为对 GetEnumName()的调用的一部分,我收到编译器错误:

  GetEnumName(TypeInfo(TMyEnum), Ord(aValue));

错误:“E2134:类型'TMyEnum'没有typeinfo”

为什么会这样?

我知道只有在启用 $ M 编译器选项的情况下编译类或者(从某些类派生,例如 TPersistent )时类只有typeinfo但是我没想到为enum类型设置typeinfo有任何特殊条件。

3 个答案:

答案 0 :(得分:30)

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

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

答案 1 :(得分:21)

枚举不支持类型信息,其中指定的特定序数值导致枚举成员的序数值与编译器通常分配的序数值不同。

如果特定值是必需的或需要的,则必须插入“未使用的”枚举成员以根据需要“填充”枚举。例如(仅用于强调的附加缩进):

  type
    TMyEnum = (
                meNOTUSED1,   {= 0}
               meFirstValue,  {= 1} 
               meSecondValue,
               meThirdValue
              );

然后可以使用子范围“过滤”未使用的初始值:

   TValidMyEnum = meFirstValue..meThirdValue;

虽然您可能希望考虑重命名原始枚举类型,以便在整个项目中使用您的子范围类型。

如果枚举包含“gap”,则子范围是不够的:

  type
    TMyEnum = (
                meNOTUSED1,   {= 0}
               meFirstValue,  {= 1} 
               meSecondValue,
               meThirdValue,
                meNOTUSED2,
               meFinalValue   {= 5}
              );

在这种情况下,没有简单的方法来扩展编译时范围检查以排除未使用的成员,但是几种集合类型将简化实现任何必要的运行时检查的业务:

  type
    TMyEnums = set of TMyEnum;

  const
    meNOTUSED      = [meUNUSED1, meUNUSED2]; //  .. etc as required
    meValidValues  = [Low(TMyEnum)..High(TMyEnum)] - meNOTUSED;


  if NOT (aValue in meValidValues) then
     // etc

答案 2 :(得分:0)

当您想将枚举转换为特定值(并返回)时,我通常创建一个数组const,每个枚举值具有所需的值:

Const MyEnumValues: array[TMyEnum] of integer = (1,2,5);

这样,当枚举扩展时,您会得到一个编译器错误,指出您缺少数组值。

请注意,在更改枚举顺序时,必须相应地更改值。

要获取枚举值的“值”,只需输入:

Value := MyEnumValues[myenum];

要获取基于“值”的枚举值,只需循环MyEnumValues的值即可:

Function GetEnumByValue(value:integer): TMyEnum;
Var
  myenum: TMyEnum;
Begin
  For myenum = low(TMyEnum) to high(TMyEnum) do
    If MyEnumValues[myenum] = value then
      exit(myenum);
  Raise exception.create(‘invalid value for tmyenum’);
End;