Reputation: 8043
I have defined an InRange
function on my enumerator type. The function should return True
if the passed integer parameter can be converted to the enumerator type.
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;
On compilation, at the line (AValue >= Low(TMyEnum))
, I get the following error:
[dcc32 Error] Unit1.pas(34): E2008 Incompatible types
I did some tests but I really don't understand what's wrong... i.e:
AValue
parameter type of InRange
function to Byte
, ShortInt
, Word
, SmallInt
, LongWord
, Cardinal
, LongInt
, Integer
and Int64
, but it raises the same error on compiling.TMyEnum = 0..1;
, it compiles without errors.Upvotes: 2
Views: 852
Reputation: 6015
You can also use generics instead of helpers to make InRange
support all enumeration types:
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.
That produces:
False
True
Exception: InRange does not support discontinuous enumerations.
Notice that your current approach will return True
for AValue
=2 if it was implemented for TMyEnum3
.
Upvotes: 4
Reputation: 8243
You can't compare an enumerated value with an integer directly. You'll have to convert the enumerated value to an integer value in order to do the comparison:
class function TMyEnumHelper.InRange(AValue : integer) : Boolean;
begin
Result :=
(AValue >= Ord(Low(TMyEnum))) and
(AValue <= Ord(High(TMyEnum)));
end;
Notice the added "ord" cast, which converts its "parameter" (the expression within the parentheses) to an integer value.
The reason your
TMyEnum = 0..1;
works is that this isn't an enumeration, but an integer sub-range, and thus the base type of TMyEnum is an integer and not an enumeration.
Upvotes: 7