Jump to content
dummzeuch

SafeGetEnumName a safer implementation of TypInfo.GetEnumName

Recommended Posts

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

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

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

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×