0

My goal is to create and generate random values for an object(s). For that I'm going through all it's fields and setting random values based on the field type. For instance if I find an integer field I give a random integer value, if I find a string I have a method that generates random string values and so on. But I have a problem with enums. I know that for non linear enums like:

TTypeNonLiear = (tnlNone = 1, tnlOther = 5, tnlAnother = 10);

RTTI does not have information about the fieldtype. So I will just skip it, no problem, but I'd like to solve the problem for linear enums types:

TTypeLiear = (tlUnknown = 0, tlOther = 1, tlAnother = 2);

If I use something like code for linear enums: Ord(Low(TTypeLiear)) or Ord(High(TTypeLiear)) I can get the ranges that I need to make it random but how to call Low and High for a field that I got the information from RTTI.

This would be a sample code:

type
  {+M}
  TTypeNonLiear = (tnlNone = 1, tnlOther = 5, tnlAnother = 10);
  TTypeLiear = (tlUnknown = 0, tlOther = 1, tlAnother = 2);

  TObjectX = class(TObject)
    FNonLinearEnum: TTypeNonLiear;
    FLinearEnum: TTypeLiear;
  end;

procedure TForm45.btn2Click(Sender: TObject);
var
  CurContext: TRttiContext;
  Test: TObjectX;
  CurClassType: TRttiType;
  CurFields: TArray<TRttiField>;
  I: Integer;
  Field: TRttiField;
  TypeValue: Integer;
  LFieldPointer: Pointer;
  TypedSmallInt: SmallInt;
begin
  Test := TObjectX.Create;

  CurContext := TRttiContext.Create;
  CurClassType := CurContext.GetType(Test.ClassType);
  CurFields := CurClassType.GetFields;

  //Here you can set any integer value you'd like to set in the type field. For example the result of query (AsInteger, AsOrdinal)
  TypeValue := 1;
  for I := 0 to Length(CurFields) -1 do
  begin
    Field := CurFields[I];
    if Assigned(Field.FieldType) and (Field.FieldType.TypeKind = tkEnumeration) then
    begin
      //Here is the solution, I change the value direct in the field position
      LFieldPointer := Pointer(PByte(Test) + Field.Offset);
      TypedSmallInt := {HERE I WANNA GENERATE THE RANDOM VALUE};
      Move(TypedSmallInt, LFieldPointer^, Field.FieldType.TypeSize);
    end;
  end;
end;
Rodrigo Farias Rezino
  • 2,687
  • 3
  • 33
  • 60
  • I would omit the explicit values: `TTypeLiear = (tlUnknown, tlOther, tlAnother);` – Uli Gerhardt Mar 12 '18 at 15:43
  • 2
    Are you tried using the `TRttiEnumerationType` class? `LMin := TRttiEnumerationType(Field.FieldType).MinValue;` `LMax := TRttiEnumerationType(Field.FieldType).MaxValue;` – RRUZ Mar 12 '18 at 15:56
  • Perfect RRUZ, this is exactly what I was looking for, I didn't know the existence of it. Can you create an answer ? – Rodrigo Farias Rezino Mar 12 '18 at 15:57
  • 1
    The documentation is wrong. It says "enumerated constants with a specific value do not have RTTI". What it should say is "enumerated types with non-contiguous ordinal values, min ordinal value not equal to zero, or non-monotonic ordinal values do not have RTTI. – David Heffernan Mar 12 '18 at 16:10
  • @DavidHeffernan, [from the horses mouth](https://stackoverflow.com/a/1420649/576719): *Discontiguous enumerations and enumerations which don't start at zero don't have typeinfo.* – LU RD Mar 12 '18 at 17:13
  • @LURD Too bad the documentation says something else – David Heffernan Mar 12 '18 at 17:16

1 Answers1

6

The TRttiEnumerationType class can be used to retrieve specific information about enumerated types like the minimum and maximum values allowed.

Try this sample

LMin:= TRttiEnumerationType(Field.FieldType).MinValue;
LMax:= TRttiEnumerationType(Field.FieldType).MaxValue;
RRUZ
  • 134,889
  • 20
  • 356
  • 483
  • I know that it is not related here, but I did not find any way to contact you. I'm using the `vclstylesinno.dll` 1.5.4.1 version, but it is not loading the style for scroll bars, for example in browse dialog, the scroll bar will not have the style. and Also in unistaller, the style will not affect the window frame. Is there any new version or any fix please? – Inside Man Sep 15 '20 at 05:40