2
votes

I'm trying to parse objects to XML in Delphi, so I read about calling the object's ClassInfo method to get its RTTI info.

The thing is, this apparently only works for TPersistent objects. Otherwise, I have to specifically add a compiler directive {$M+} to the source code for the compiler to generate RTTI info.

So I happily added the directive, only to find that, even if it did return something from the ClassInfo call (it used to return nil), now I cannot retrieve the class' properties, fields or methods from it. It's like it created the object empty.

Any idea what am I missing here? Thanks!

4

4 Answers

7
votes

Did you put those properties and methods into the published section?

Besides that, 'classical' RTTI ($TYPEINFO ON) will only get you information on properties, not on methods. You need 'extended' RTTI ($METHODINFO ON) for those.

Good starting point for extended RTTI: David Glassborow on extended RTTI

(who would believe that just this minute I finished writing some code that uses extended RTTI and decided to browse the Stack Overflow a little:))

3
votes

RTTI will only show you published properties,etc. - not just public ones.

Try your code with a TObject and see what happens - if that isn't working, post your code because not everyone is psychic.

3
votes

Have you considered using the TXMLDocument component? It will look at your XML and then create a nice unit of Delphi classes that represents your XML file -- makes it really, really easy to read and write XML files.

0
votes

As for the RttiType problem returning only nil, this probably occurs for one reason: in your test, you did not instantiate the class at any time. The compiler, because it never has a reference to this class (because it is not an instance at all), simply removes it from the information as a form of optimization. See the two examples below. The behavior is different when you have the class instantiated at some point in your code or not.

Suppose the following class:

type
  TTest = class
  public
    procedure Test;
  end;

and the following code below:

var
  LContext: TRttiContext;
  LType: TRttiType;
  LTest: TTest;
begin
  LContext := TRttiContext.Create;
  for LType in LContext.GetTypes do
  begin
    if LType.IsInstance then
    begin
      WriteLn(LType.Name);
    end;
  end;
end;

so far, TTest class information is not available for use by RTTI. However, when we create at some point, within the application, then a reference is created for it within the compile, which makes this information available:

var
  LContext: TRttiContext;
  LType: TRttiType;
  LTest: TTest;
begin
  LTest := TTest.Create; //Here i´m using TTest.
                         //Could be in another part of the program

  LContext := TRttiContext.Create;
  for LType in LContext.GetTypes do
  begin
    if LType.IsInstance then
    begin
      WriteLn(LType.Name);
    end;
  end;
end;

At that point, if you use LContext.FindType ('TTest'), there will not be a nil return, because the compiler kept reference to the class. This explains the behavior you were having in your tests.