Rtti accessing fields and properties in complex data structures

前端 未结 3 1176
情书的邮戳
情书的邮戳 2020-12-28 11:34

As already discussed in Rtti data manipulation and consistency in Delphi 2010 a consistency between the original data and rtti values can be reached by accessing members by

3条回答
  •  北荒
    北荒 (楼主)
    2020-12-28 12:18

    You seem to be misunderstanding the way an instance pointer works. You don't store a pointer to the field, you store a pointer to the class or the record that it's a field of. Object references are pointers already, so no casting is needed there. For records, you need to obtain a pointer to them with the @ symbol.

    Once you have your pointer, and a TRttiField object that refers to that field, you can call SetValue or GetValue on the TRttiField, and pass in your instance pointer, and it takes care of all the offset calculations for you.

    In the specific case of arrays, GetValue it will give you a TValue that represents an array. You can test this by calling TValue.IsArray if you want. When you have a TValue that represents an array, you can get the length of the array with TValue.GetArrayLength and retrieve the individual elements with TValue.GetArrayElement.

    EDIT: Here's how to deal with record members in a class.

    Records are types too, and they have RTTI of their own. You can modify them without doing "GetValue, modify, SetValue" like this:

    procedure ModifyPoint(example: TExampleClass; newXValue, newYValue: integer);
    var
      context: TRttiContext;
      value: TValue;
      field: TRttiField;
      instance: pointer;
      recordType: TRttiRecordType;
    begin
      field := context.GetType(TExampleClass).GetField('FPoint');
      //TValue that references the TPoint
      value := field.GetValue(example);
      //Extract the instance pointer to the TPoint within your object
      instance := value.GetReferenceToRawData;
      //RTTI for the TPoint type
      recordType := context.GetType(value.TypeInfo) as TRttiRecordType;
      //Access the individual members of the TPoint
      recordType.GetField('X').SetValue(instance, newXValue);
      recordType.GetField('Y').SetValue(instance, newYValue);
    end;
    

    It looks like the part you didn't know about is TValue.GetReferenceToRawData. That will give you a pointer to the field, without you needing to worry about calculating offsets and casting pointers to integers.

提交回复
热议问题