dummzeuch 1505 Posted June 21 I just had the need for a safer version of Delphi's GetEnumName, which checks whether the enum value passed to it is actually valid. This is what I came up with: // P must point to the length field (that is the first byte) of a ShortString function AfterShortString(const P: Pointer): Pointer; inline; begin Result := Pointer(IntPtr(P) + PByte(P)^ + 1); end; function SafeGetEnumName(TypeInfo: PTypeInfo; Value: Integer): string; var P: Pointer; T: PTypeData; begin if TypeInfo^.Kind = tkInteger then begin Result := IntToStr(Value); Exit; end; T := GetTypeData(GetTypeData(TypeInfo)^.BaseType^); if (TypeInfo = System.TypeInfo(Boolean)) or (T^.MinValue < 0) then begin // LongBool/WordBool/ByteBool have MinValue < 0 and // arbitrary content in Value; Boolean has Value // in [0, 1] } Result := BooleanIdents[Value <> 0]; if SameText(HexDisplayPrefix, '0x') then Result := LowerCase(Result); end else begin if (Value < T.MinValue) or (Value > T.MaxValue) then Result := Format('OutOfBounds(%d)', [Value]) else begin P := @T^.NameList; while Value <> 0 do begin P := AfterShortString(P); Dec(Value); end; {$IFDEF UNICODE} Result := _UTF8ToString(P); {$ELSE} Result := PShortString(P)^; {$ENDIF} end; end; end; (read on in the blog post) Share this post Link to post
baka0815 12 Posted June 24 What's not working is if the enum has gaps: type TMyEnum = ( meVal1 = 1 , meVal2 = 2 , meVal5 = 5 ); 3 and 4 are both "in range", but invalid. Share this post Link to post
dummzeuch 1505 Posted June 24 Hm, yes. But GetEnumName doesn't work for enums with explicitly assigned values. program Project1; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils, System.TypInfo; type TBla = (a5 = 5, a7 = 7); TBlub = (b5, b7); begin WriteLn(GetEnumName(TypeInfo(TBlub), Ord(b5))); WriteLn(GetEnumName(TypeInfo(TBla), Ord(a5))); end [dcc32 Error] Project1.dpr(19): E2134 Type 'TBla' has no type info Share this post Link to post