1

I'm having trouble getting an enumerated type based on it's name, rather than ordinal value. I need to do this within an RTTI loop of a class' properties. I've tried using GetEnumName and TRTTIEnumerationType.GetName, but I can't seem to fit these things together from a TRTTIProperty instance.

Help please? (skeleton code example below)

    uses
      RTTI, TypInfo;
    
    type 
      TCustomColor = (ccBlack, ccBrown, ccBlue);
    
      TMyClass = class
      public
        property CustomColor: TCustomColor;
      end;
    
    procedure Output;
    var
      rc : TRTTIContext;
      rt : TRTTIType;
      rp : TRTTIProperty;
      mc : TMyClass;
    begin
      mc.CustomColor := ccBlue;
      rt := rc.GetType(mc.ClassType);
      for rp in rt.GetProperties do
        if rp.PropertyType.TypeKind = tkEnumeration then
        begin
          // TODO: Retrieve 'ccBlue' from the property
        end;
    end;
    
    procedure Input;
    var
      n, s : String;
      o : TObject;
      rc : TRTTIContext;
      rt : TRTTIType;
    begin
      n := 'CustomColor';
      s := 'ccBlue';
      // NOTE: o is instantiated from a string of it's classtype
      o := (rc.FindType('MyClass') as TRTTIInstanceType).MetaClassType.Create;
      rt := rc.GetType(o.ClassType);
      rt.GetProperty(n).SetValue(o, ???);  // TODO: set o.CustomColor appropriately
    end;

Griffyn
  • 173
  • 1
  • 11
  • See [Generic functions for converting an enumeration to string and back](https://stackoverflow.com/q/31601707/576719) – LU RD Nov 19 '18 at 06:09
  • @LU RD That doesn't answer my question of how to connect that to a TRTTIProperty, keeping in mind that my code has no idea of the enumeration type - generics seem to require a compiled type, but I only have this at runtime. – Griffyn Nov 19 '18 at 06:27
  • 1
    Take a look at the help for TValue. In extended RTTI, properties are retrieved or set using a TValue. e.g. `MyTValue := rp.GetValue(mc); s := MyTValue.ToString;`. This does not work the other way, though. Oh, and using meaningful variable names helps people understand your code too. – Rudy Velthuis Nov 19 '18 at 08:46
  • I'm still not clear what you are trying to do. What are the input variables, and what are the desired output variables. It's odd that you say that you start with an enum, but you also say that you don't know the type of the enum. So are you just trying to convert between integer ordinal value and the string name of the enumerated type of a named property? – David Heffernan Nov 19 '18 at 09:00
  • Well, your code seems to suggest that you do know the object type at run time, at least too the extent needed by generics. I have done this based on generics and RTTI, mainly for creating TlistCheckboxes and such like on the fly. The code is to complex (and cluttered with unnecessary stuff for an answer) to publish, but basically I iterate from min to max value and do a string compare to set a value based on its string value. I am sure it can be done without generics, but not sure what the point would be. I certainly don't intend to remove generics from my code. – Dsm Nov 19 '18 at 09:43
  • The project is attempting to convert a complex object into JSON, so I'm looping through the published properties, and delving into referenced objects and generic object lists and taking their published properties too. This code has no idea about the enum types of all of the referenced objects. I can easily get and set the ordinal value of these enum properties, but as the project will likely have a long development/publishing cycle, I would prefer the JSON to store the enum names to allow for deletion of enum values without invalidating any stored JSON. – Griffyn Nov 19 '18 at 21:35
  • And before you suggest SvSerializer (which works well in other projects), it doesn't work here as it doesn't output referenced object class names, which is important. – Griffyn Nov 19 '18 at 21:38

2 Answers2

3

Please note that in newer versions of Delphi, you can do this:

S:=TRttiEnumerationType.GetName(o.CustomColor)
HeartWare
  • 7,464
  • 2
  • 26
  • 30
2

Thanks to Rudy, who put me on the right track. Being able to get the PTypeInfo of the property gave me the link I needed.

    var
      rp: TRTTIProperty;
      o : TMyClass;
      s : String;
    begin
      o.CustomColor := ccBlue;
      [...]  // loop through and assign rp to the TMyClass.CustomColor property
      s := GetEnumName(rp.GetValue(o).TypeInfo, rp.GetValue(o).AsOrdinal));
      WriteLn(s);   // 'ccBlue';
Griffyn
  • 173
  • 1
  • 11