为什么我会收到“类型没有类型信息”枚举类型错误

发布于 2024-08-04 20:49:10 字数 590 浏览 7 评论 0原文

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

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

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

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

ERROR: "E2134: Type 'TMyEnum' has no typeinfo"

这是为什么?

我知道类只有在启用 $M 编译器选项的情况下编译时才具有类型信息,或者(从某个类派生,例如 TPercient),但我没有认为具有枚举类型的类型信息有任何特殊条件。

I have declared the following enum type in which I want the first member to have the ordinal value of 1 (one) rather than the usual 0 (zero):

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

If I call TypeInfo(), e.g. as part of a call to GetEnumName(), I get a compiler error:

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

ERROR: "E2134: Type 'TMyEnum' has no typeinfo"

Why is this?

I know that classes only have typeinfo if they are compiled with the $M compiler option enabled or (derive from some class which was, such as TPersistent) but I didn't think there were any special conditions for having typeinfo for enum types.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

仙气飘飘 2024-08-11 20:49:10

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

我考虑过为 Delphi 2010 实现一个 tkDiscontigouslyEnumeration (或者可能更好的命名成员),但考虑到它们的相对稀缺性和枚举的困难,好处似乎很小 - 如何有效地对范围进行编码?某些编码对于某些场景更好,而对于另一些场景则更差。

Discontiguous enumerations, and enumerations which don't start at zero, don't have typeinfo. For typeinfo to be implemented, it would need to be in a different format from the existing tkEnumeration, owing to backward compatibility issues.

I considered implementing a tkDiscontiguousEnumeration (or possibly better named member) for Delphi 2010, but the benefit seemed small considering their relative scarcity and the difficulties in enumeration - how do you encode the ranges efficiently? Some encodings are better for some scenarios, worse for others.

无戏配角 2024-08-11 20:49:10

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

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

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

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

   TValidMyEnum = meFirstValue..meThirdValue;

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

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

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

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

  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

Type information is not supported for enums where specific ordinal values are assigned that result in enum members having ordinal values that are different to those that would normally be assigned by the compiler.

If specific values are essential or desirable, "unused" enum members will have to be inserted to "pad" the enum as required. e.g (additional indentation for emphasis only):

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

A subrange can then be used to "filter" out the unused initial value:

   TValidMyEnum = meFirstValue..meThirdValue;

Although you might then wish to consider renaming the original enum type so that your subrange type may be used throughout your project.

A subrange isn't sufficient if the enum contains "gaps":

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

In this case there is no simply way to extend compile-time range checking to exclude the unused members, but a couple of set types will simplify the business of implementing any necessary runtime checks:

  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
弱骨蛰伏 2024-08-11 20:49:10

当您想要将枚举转换为特定值(或返回)时,我通常创建一个常量数组,其中每个枚举值都有所需的值:

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;

When you want to convert enums into specific values (and back) I useally create an array const, with the desired values per enum value:

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

This way when the enum gets expanded you get an compiler error stating you are missing an array value.

Please note when changing the order of the enums, you must change the values accordingly.

To get the ‘value’ for an enum values just write:

Value := MyEnumValues[myenum];

And to get the enum value based on the ‘value’ just loop though the values of 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;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文