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):
我已经声明了以下枚举类型,其中我希望第一个成员的序数值为1(一)而不是通常的0(零):
type TMyEnum = ( meFirstValue = 1, meSecondValue, meThirdValue );
If I call TypeInfo(), e.g. as part of a call to GetEnumName(), I get a compiler error:
如果我调用TypeInfo(),例如作为对GetEnumName()的调用的一部分,我得到一个编译器错误:
GetEnumName(TypeInfo(TMyEnum), Ord(aValue));
ERROR: "E2134: Type 'TMyEnum' has no typeinfo"
错误:“E2134:类型'TMyEnum'没有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.
我知道如果类在编译时启用了$ M编译器选项,或者(从某些类派生,例如TPersistent),类只有typeinfo,但我认为没有任何特殊条件可以为枚举类型提供typeinfo。
2 个解决方案
#1
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.
不以零开头的不连续枚举和枚举没有typeinfo。对于要实现的typeinfo,由于向后兼容性问题,它需要采用与现有tkEnumeration不同的格式。
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.
我考虑过为Delphi 2010实现一个tkDiscontiguousEnumeration(或者可能更好的命名成员),但考虑到它们的相对稀缺性和枚举的困难,它的好处似乎很小 - 你如何有效地编码范围?某些编码对某些情况更好,对其他情况则更糟。
#2
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
#1
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.
不以零开头的不连续枚举和枚举没有typeinfo。对于要实现的typeinfo,由于向后兼容性问题,它需要采用与现有tkEnumeration不同的格式。
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.
我考虑过为Delphi 2010实现一个tkDiscontiguousEnumeration(或者可能更好的命名成员),但考虑到它们的相对稀缺性和枚举的困难,它的好处似乎很小 - 你如何有效地编码范围?某些编码对某些情况更好,对其他情况则更糟。
#2
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