23

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

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

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

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

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

为什么是这样?

我知道只有在启用$M编译器选项或(从某些类派生,例如TPersistent )的情况下编译类时才具有 typeinfo ,但我认为没有任何特殊条件可以为枚举类型提供 typeinfo 。

4

3 回答 3

37

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

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

于 2009-09-14T10:00:47.383 回答
23

对于分配了特定序数值的枚举不支持类型信息,这会导致枚举成员的序数值与编译器通常分配的序数值不同。

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

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

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

   TValidMyEnum = meFirstValue..meThirdValue;

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

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

  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
于 2009-09-14T09:42:12.117 回答
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;
于 2019-09-17T19:24:03.480 回答