Hi all

Hi all,

Is it possible to figure out whether a type's property has a 'stored' flag or not, preferably without having to create an instance of that type?

Like this:

property Value: string read GetValue write SetValue stored ShouldStoreValue;

with a private function ShouldStoreValue: Boolean; in the same class.

We've got this calculation core working with a fairly elaborate internal data structure. We're using NativeXML's ObjectToNode routines for saving and loading the data structure; this works beautifully.

Now other parties are going to be communicating with that calculation core, and the easiest way of doing that is via the data structure generated by NativeXML.  Ideally, we would like to generate something akin to an XSD, an XML Schema Definition, for it.

Using the 'new' RTTI units, this appears out to be quite feasible. The only catch is that we rely quite often on the 'stored' flag of a property to determine whether that property needs to be persisted or not; and I'd like to be able to see whether a property has a 'stored' flag, and if possible which method (or which constant) is used to determine storage.

Does anybody know if this is possible?

Comments

  1. Qing-Shan Xiao Thanks, but as I said, I'd like to know this without having to create an instance of that type. IsStoredProp requires an actual instance.

    ReplyDelete
  2. Did you try the stuff in the `TypInfo` unit?

    ReplyDelete
  3. well, according to the function IsStoredProp(Instance: TObject; PropInfo: PPropInfo): Boolean;
    in TypInfo.pas unit, you can see why it need instance parameter. As i read it (it's assembly), only the function declare as Static Method can judge true or false at runtime without instance.
    So if you declare ShouldStoreValue as static, you can try the tricky as below:
    TYPINFO.IsStoredProp(nil, PropInfo);
    theoretically will success. 
    On the other hand, If it's a normal method, it need instance address + offset. Conclusion is No possible to check true or false WITHOUT instance.
    BTW, you got to look up the IsStoredProp function implement to make sure. I just fast review it and not very sure the correction.

    ReplyDelete
  4. If you want to assume that only "stored false" should NOT be stored, and anything else SHOULD, then you do NOT need the instance. Otherwise you do as Qing-Shan Xiao mentioned. However if you're fine with that assumption then here's how:

    program Project1
    {$APPTYPE CONSOLE}
    uses
      System.SysUtils, System.TypInfo, System.Rtti;
    type
      TFoo = class
      private
        FValue: integer;
        FStored: boolean;
        function GetStored: boolean;
      public
        property NoStored: integer read FValue;
        property StoredTrue: integer read FValue stored True;
        property StoredFalse: integer read FValue stored False;
        property StoredField: integer read FValue stored FStored;
        property StoredFunc: integer read FValue stored GetStored;
      end;
    { TFoo }
    function TFoo.GetStored: boolean;
    begin
      result := False;
    end;

    function IsPropStored(const prop: TRttiProperty): boolean;
    var
      ip: TRttiInstanceProperty;
    begin
      ip := prop as TRttiInstanceProperty;
      result := ip.PropInfo^.StoredProc <> nil;
    end;
    procedure CheckStoredProperties(const c: TClass);
    var
      ctx: TRttiContext;
      typ: TRttiType;
      inst: TRttiInstanceType;
      prop: TRttiProperty;
    begin
      ctx := TRttiContext.Create;
      typ := ctx.GetType(c);
      inst := typ as TRttiInstanceType;
      for prop in inst.GetProperties() do
      begin
        Write(prop.Name + ': ');
        if IsPropStored(prop) then
          Write(' stored')
        else
          Write(' not stored');
        WriteLn;
      end;
    end;
    begin
      try
        CheckStoredProperties(TFoo);
      except
        on E: Exception do
          Writeln(E.ClassName, ': ', E.Message);
      end;
      ReadLn;
    end.

    ReplyDelete
  5. Asbjørn Heid Thanks a lot, stored False is indeed the most important info I needed. I hadn't really figured out all of the stuff in TypInfo.

    ReplyDelete
  6. Qing-Shan Xiao it makes sense for IsStoredProp to require an instance, since it will try to execute ShouldStoreValue and return the result. I want to know if the property had stored False or stored ShouldStoreValue. It would seem it's only possible to see if the property has stored False without instance.

    ReplyDelete
  7. Actually, it might be possible to compare the StoredProc pointer to all the methods, to see if one matches. I'll try that tomorrow.

    ReplyDelete
  8. So I tried looking at the StoredProc pointer, and I can differentiate between three states:
    1. nil, which means stored False;
    2. Pointer(1), which means that no stored flag was specified; and 
    3. an actual pointer, which means that a method was specified; and the pointer seems to point at the relevant method's CodeAddress. However, we always use private methods for that, and those don't seem to be enumerated by GetMethods.
    Still, those three states are basically what I needed: don't include an element when StoredProc = nil; when StoredProc = Pointer(1) make it compulsory, and make it optional otherwise when it's a pointer.
    Thanks a lot to all who helped! Qing-Shan Xiao Jeroen Wiert Pluimers Asbjørn Heid

    ReplyDelete
  9. Martijn Coppoolse Thanks. I added your solution to my blog post.

    ReplyDelete

Post a Comment