Jump to content
Sign in to follow this  
PiedSoftware

Any way to get RTTI for non-zero-based enumerated types?

Recommended Posts

Posted (edited)

Hi

 

I have been using a generic record to convert combo-boxes to enumerated type. But Delphi spits the dummy if the type has any numbers specified.

For example with this code the compiler throws up the error message "E2134 Type 'TDDArrangementId' has no type info. In the generic type TypeInfo(T) returns nil.

type
  TDDArrangementId = (daOutstanding = 1, daWeeklyGap, daAmount, daGapAmount);
...

procedure Test;
var ti: PTypeInfo;
begin
  ti := TypeInfo(TDDArrangementId);


But removing the " = 1" makes  it all build and run just fine.

Can anyone confirm that Delphi's rtti system simply does not handle enumerated types if they are not zero-based?

I'm using 10.4
---
Mark

Edited by PiedSoftware

Share this post


Link to post
14 minutes ago, PiedSoftware said:

Can anyone confirm that Delphi's rtti system simply does not handle enumerated types if they are not zero-based?

Saly: yes, that's the case.

Share this post


Link to post

Yes. The only solution is to start the enum from 0 (why using 1 as starting value?)

Share this post


Link to post

My approach to these types of problems is to add a record helper for the enumeration that handles the conversion from and to Integer.

type
  TDDArrangementId = (daOutstanding, daWeeklyGap, daAmount, daGapAmount);
  TDDArrangementIdHelper = record helper for TDDArrangementId
  private
    function GetAsInteger: Integer;
    procedure SetAsInteger(const Value: Integer);
  public
    property AsInteger: Integer read GetAsInteger write SetAsInteger;
  end;

function TDDArrangementIdHelper.GetAsInteger: Integer;
begin
  Result := Ord(Succ(Self));
end;

procedure TDDArrangementIdHelper.SetAsInteger(const Value: Integer);
begin
  Self := TDDArrangementId(Pred(Value));
end;

The usage would then look like this:

var
  myVar: TDDArrangementId;
begin
  myVar.AsInteger := 1;
  Assert(myVar = daOutstanding);
  Inc(myVar);
  Assert(myVar = daWeeklyGap);
  Assert(myVar.AsInteger = 2);
end.

 

  • Like 2

Share this post


Link to post
On 4/1/2022 at 4:56 PM, Fr0sT.Brutal said:

Yes. The only solution is to start the enum from 0 (why using 1 as starting value?)

The values correspond with values on a database. 

Share this post


Link to post
On 4/1/2022 at 8:01 PM, Uwe Raabe said:

My approach to these types of problems is to add a record helper for the enumeration that handles the conversion from and to Integer.

Thanks. That would be useful. I have decided to do it differently in this case

Share this post


Link to post
2 hours ago, PiedSoftware said:

The values correspond with values on a database. 

You may use the following trick which I recently invented and applied to all my projects:

1) TEnumNullable = (enNone, enFoo, enBar);

2) TEnum = enFoo..enBar; // or Succ(Low(TEnumNullable))..High(TEnumNullable)

 

this has following benefits:

- RTTI features

- "Null" value that won't cause range check errors in FPC like usual TEnum(-1)

- "Null" value that is NULL (zero) actually - ZeroMemory, Default(), Class.Create init fields with this value

- two types so you can differentiate where null is expected and where not

- simple and obvious DB_Value_Of_Enum = Ord()

  • Like 1

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
Sign in to follow this  

×