Get constant fields from a class using RTTI
Asked Answered
Y

3

3

Can I enumerate the constants(const) from a class?

I have tried

MyClass = class
const
  c1 = 'c1';
  c2 = 'c2';
  c3 = 'c3';
end;

procedure GetConst();
var
  ctx: TRttiContext;
  objType: TRttiType;
  field: trttifield;
  s: string;
begin
  ctx := TRttiContext.Create;
  objType := ctx.GetType(MyClass.ClassInfo);
  for field in objType.GetDeclaredFields do
    s:= field.Name;
end;

I would like to get c1, c2, c2.

Is this possible?

edit: what I want to do is define some keys for some external symbols(for a cad program)

symbol1=class
    const
    datafield1='datafield1';
    datafield2='datafield2';
end;
symbol2=class
    const
    datafield21='datafield21abc';
    datafield22='datafield22abc';
end

I don't like to use fields for this because I prefer not to seperate declareration and initialization. I can't use an enum since I can't define the value as a string.

Yonita answered 21/9, 2012 at 13:4 Comment(5)
probably not. Probably at compile time there are no more constants but the immediate values instead. there is little sense to kkep them separatelyTexas
If you did an enum, you could add TypInfo to your uses clause and then use GetEnumName and GetEnumValue to translate between the string and ordinal values.Promise
but enum value can only be integer right? I need stringYonita
GetEnumName translates the int to a string. GetEnumValue translates a string to the enum int. So even though an enum is a series of ints, you can use them in your code like strings.Promise
I'll add an example as an answer so you see how to translate an enum to a string and back to an enum...Promise
M
5

You can't get at those constants through RTTI. I suspect your best solution will be to use attributes instead. Not only will that have the benefit of actually working, I think it sounds like a cleaner and simpler solution to your problem.

Madid answered 21/9, 2012 at 14:55 Comment(2)
Attributes on what exactly? What should they contain?Yonita
Attributes on each class that contain its keys.Madid
P
4

If you use an enum, you can use TypInfo to translate strings to the enum values, and the enum values to strings in your code:

type
  TDataFieldName = (datafield1, datafield2, datafield3);

uses TypInfo;

var df: TDataFieldName;
begin
  df := TDataFieldName(GetEnumValue(TypeInfo(TDataFieldName), 'datafield1'));

  ShowMessage(GetEnumName(TypeInfo(TDataFieldName), Ord(df)));

  case df of
    datafield1:;
    datafield2:;
    datafield3:;
  end;
end;

(Typed from my head -- haven't tested this...)

This way the cad program can pass strings to your Delphi app, and you can translate them to the enum, or you can translate the enum to a string to pass to the cad program. It's also easy to do a case statement where the original value was a string, converted to an enum. This has come in very handy since Delphi doesn't support string case statements.

Promise answered 21/9, 2012 at 15:47 Comment(2)
Does RTTI impose much overhead in this situation as compared to say var fields in a class? Is there a common base type for enums so I can make a common method to handle symbol1 and symbol2Yonita
I've never analyzed the RTTI overhead -- but I commonly use this so that I can use a case statement with the string converted to an enum (see edit above). I've never had any performance issues.Promise
Y
0

I've decided to use fields in my classes. Since I don't want to duplicate fields for declaration and initialization, i'm using rtti to initialize fields to the value of the field.

The benefits are: No rtti overhead on runtime. rtti is only performed during app startup. Also I get to use inheritance which is very useful for my project.

Yonita answered 22/9, 2012 at 20:54 Comment(3)
That's nice. Glad that you have a solution. However, this is not an answer to the question that you asked. Remember that you asked if RTTI could be used to obtain class constants.Madid
Regarding solutions to your problem as opposed to answers to the question you asked, did you consider a method call to retrieve these field names? This would likely be a virtual class method if you have a common ancestor. Otherwise it would probably need to be an interface.Madid
I may not have communicated this clearly, but I need to be able to enumerate and have keys readily available like key1.field1. I could add a method to use rtti, but seems like a detail.Yonita

© 2022 - 2024 — McMap. All rights reserved.