如何检查整数是否可以转换为枚举类型值?
How to check if an integer can be converted to an enumeration type value?
我在我的枚举器类型上定义了一个 InRange
函数。如果传递的整数参数可以转换为枚举器类型,则该函数应该return True
。
TMyEnum = (eA, eB);
TMyEnumHelper = record helper for TMyEnum
class function InRange(AValue : integer) : Boolean; static;
end;
...
class function TMyEnumHelper.InRange(AValue : integer) : Boolean;
begin
Result :=
(AValue >= Low(TMyEnum)) and
(AValue <= High(TMyEnum));
end;
编译时,在第 (AValue >= Low(TMyEnum))
行出现以下错误:
[dcc32 Error] Unit1.pas(34): E2008 Incompatible types
我做了一些测试,但我真的不明白哪里出了问题...
即:
- 我尝试将
InRange
函数的 AValue
参数类型切换为 Byte
、ShortInt
、Word
、SmallInt
, LongWord
、Cardinal
、LongInt
、Integer
和 Int64
,但在编译时会引发相同的错误。
- 如果我将枚举器定义为
TMyEnum = 0..1;
,它编译时不会出错。
您不能直接将枚举值与整数进行比较。您必须将枚举值转换为整数值才能进行比较:
class function TMyEnumHelper.InRange(AValue : integer) : Boolean;
begin
Result :=
(AValue >= Ord(Low(TMyEnum))) and
(AValue <= Ord(High(TMyEnum)));
end;
注意添加的 "ord" 转换,它将其 "parameter"(括号内的表达式)转换为整数值。
你的原因
TMyEnum = 0..1;
有效的是这不是枚举,而是整数子范围,因此 TMyEnum 的基类型是整数而不是枚举。
您还可以使用泛型而不是助手来使 InRange
支持所有枚举类型:
uses
SysUtils, TypInfo;
type
TMyEnum1 = (me1A, me1B);
TMyEnum2 = (me2A, me2B, me2C);
TMyEnum3 = (me3A = 1, me3B = 3);
TEnum = class
class function InRange<T>(const AValue: Integer): Boolean; static;
end;
{ TEnum }
class function TEnum.InRange<T>(const AValue: Integer): Boolean;
var
TI: PTypeInfo;
TD: PTypeData;
begin
TI := TypeInfo(T);
if not Assigned(TI) then
raise Exception.Create('InRange does not support discontinuous enumerations.');
if TI^.Kind <> tkEnumeration then
raise Exception.Create('InRange only supports enumeration types.');
TD := GetTypeData(TI);
Result :=
(AValue >= TD^.MinValue) and
(AValue<=TD^.MaxValue);
end;
begin
try
Writeln(BoolToStr(TEnum.InRange<TMyEnum1>(2), true));
Writeln(BoolToStr(TEnum.InRange<TMyEnum2>(2), true));
Writeln(BoolToStr(TEnum.InRange<TMyEnum3>(2), true));
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
Readln;
end.
产生:
False
True
Exception: InRange does not support discontinuous enumerations.
请注意,如果为 TMyEnum3
.
实施,您当前的方法将为 AValue
=2 return True
我在我的枚举器类型上定义了一个 InRange
函数。如果传递的整数参数可以转换为枚举器类型,则该函数应该return True
。
TMyEnum = (eA, eB);
TMyEnumHelper = record helper for TMyEnum
class function InRange(AValue : integer) : Boolean; static;
end;
...
class function TMyEnumHelper.InRange(AValue : integer) : Boolean;
begin
Result :=
(AValue >= Low(TMyEnum)) and
(AValue <= High(TMyEnum));
end;
编译时,在第 (AValue >= Low(TMyEnum))
行出现以下错误:
[dcc32 Error] Unit1.pas(34): E2008 Incompatible types
我做了一些测试,但我真的不明白哪里出了问题... 即:
- 我尝试将
InRange
函数的AValue
参数类型切换为Byte
、ShortInt
、Word
、SmallInt
,LongWord
、Cardinal
、LongInt
、Integer
和Int64
,但在编译时会引发相同的错误。 - 如果我将枚举器定义为
TMyEnum = 0..1;
,它编译时不会出错。
您不能直接将枚举值与整数进行比较。您必须将枚举值转换为整数值才能进行比较:
class function TMyEnumHelper.InRange(AValue : integer) : Boolean;
begin
Result :=
(AValue >= Ord(Low(TMyEnum))) and
(AValue <= Ord(High(TMyEnum)));
end;
注意添加的 "ord" 转换,它将其 "parameter"(括号内的表达式)转换为整数值。
你的原因
TMyEnum = 0..1;
有效的是这不是枚举,而是整数子范围,因此 TMyEnum 的基类型是整数而不是枚举。
您还可以使用泛型而不是助手来使 InRange
支持所有枚举类型:
uses
SysUtils, TypInfo;
type
TMyEnum1 = (me1A, me1B);
TMyEnum2 = (me2A, me2B, me2C);
TMyEnum3 = (me3A = 1, me3B = 3);
TEnum = class
class function InRange<T>(const AValue: Integer): Boolean; static;
end;
{ TEnum }
class function TEnum.InRange<T>(const AValue: Integer): Boolean;
var
TI: PTypeInfo;
TD: PTypeData;
begin
TI := TypeInfo(T);
if not Assigned(TI) then
raise Exception.Create('InRange does not support discontinuous enumerations.');
if TI^.Kind <> tkEnumeration then
raise Exception.Create('InRange only supports enumeration types.');
TD := GetTypeData(TI);
Result :=
(AValue >= TD^.MinValue) and
(AValue<=TD^.MaxValue);
end;
begin
try
Writeln(BoolToStr(TEnum.InRange<TMyEnum1>(2), true));
Writeln(BoolToStr(TEnum.InRange<TMyEnum2>(2), true));
Writeln(BoolToStr(TEnum.InRange<TMyEnum3>(2), true));
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
Readln;
end.
产生:
False
True
Exception: InRange does not support discontinuous enumerations.
请注意,如果为 TMyEnum3
.
AValue
=2 return True