【问题标题】:Getting values from pointer to record type rtti field从指向记录类型 rtti 字段的指针中获取值
【发布时间】:2013-02-20 12:32:42
【问题描述】:

我在尝试使用 Delphi 的 RTTI 访问指向记录数据中记录类型的指针时遇到了麻烦。

请检查我一直在处理的示例代码。

  // Dummy Header
  typDummyHeader = ^tysDummyHeader;
  tysDummyHeader = record
    MessageCode : Integer;
    MessageLength : Integer;
  end;

  // Dummy record having header and trailer
  tysDummyRecord = record
    Header : tysDummyHeader;
    BotAmount : Double;
    SoldAmount : Double;
    SoldQty : Int64;
    BotQty : Int64;
    Tailer : typDummyHeader; // pointer to Dummy Header
  end;

  TclDummy = class
    class function GetFieldValue<T>(const pipInstance : Pointer;
                                const piclField : TRttiField) : string;

    class function ParseAndReturnString<T>(piclObject : T) : string;
  end;

  var
    frmRTTITest: TfrmRTTITest;

  implementation

  {$R *.dfm}

  procedure TfrmRTTITest.FormCreate(Sender: TObject);
  var
    losDummyRecord : tysDummyRecord;
  begin
    FillChar(losDummyRecord, SizeOf(tysDummyRecord), #0);
    losDummyRecord.Header.MessageCode := 5000;
    losDummyRecord.Header.MessageLength := 54433;
    losDummyRecord.BotAmount := 19.45;
    losDummyRecord.SoldAmount := 34.22;
    losDummyRecord.SoldQty := 102;
    losDummyRecord.BotQty := 334;
    losDummyRecord.Tailer := @losDummyRecord.Header;

    ShowMessage(TclDummy.ParseAndReturnString<tysDummyRecord>(losDummyRecord));
  end;

  class function TclDummy.GetFieldValue<T>(const pipInstance : Pointer;
                               const piclField : TRttiField) : string;
  begin
    case piclField.FieldType.TypeKind of
      tkFloat: Result := FloatToStr(piclField.GetValue(pipInstance).AsExtended);
      tkInt64: Result := IntToStr(piclField.GetValue(pipInstance).AsInt64);
      tkInteger: Result := IntToStr(piclField.GetValue(pipInstance).AsInteger);
      tkString: Result := Trim(piclField.GetValue(pipInstance).AsString);
    end;
  end;

  class function TclDummy.ParseAndReturnString<T>(piclObject : T) : string;
  var
    losContext : TRttiContext;
    losContextType : TRttiType;
    loclField : TRttiField;
    losRecordRTTI : TRttiRecordType;
    loclRecordField : TRttiField;
    losPointerType : TRttiPointerType;
    losValue : TValue;
  begin
    Result := EmptyStr;
    losContext := TRttiContext.Create;
    losContextType := losContext.GetType(TypeInfo(T));

    if losContextType.TypeKind = tkRecord then
    begin
      for loclField in losContextType.GetFields do
      begin
        case loclField.FieldType.TypeKind of
          tkRecord:
          begin
            losRecordRTTI := loclField.FieldType.AsRecord;
            for loclRecordField in losRecordRTTI.GetFields do
            begin
              Result := Result + '|' + GetFieldValue<T>(Addr(piclObject), loclRecordField);
            end;
          end; // tkRecord
          tkPointer:
          begin
            losPointerType := loclField.FieldType as TRttiPointerType;

            // Check only record type pointers.
            if losPointerType.ReferredType.TypeKind = tkRecord then
            begin
              losValue := loclField.GetValue(Addr(piclObject));
              if (not losValue.IsEmpty) then
              begin
                for loclRecordField in losPointerType.ReferredType.GetFields do
                begin
                  // Result := Result + '|' + ???????????
                end;
              end;
            end;
          end; // tkPointer
          else
            Result := Result + '|' + GetFieldValue<T>(Addr(piclObject), loclField);
        end;
      end;
    end;
    losContext.Free;
  end;

在上面的示例中,当字段为tkPointer 指向记录类型时,我如何从中读取值?

【问题讨论】:

  • 基本上我要做的是得到一个与记录中所有成员连接的字符串,即使它包含嵌套记录。
  • 这不是 ParseAndReturnString 已经做的吗?递归调用它。
  • @DavidHeffernan 我需要从指针类型中获取值。请用???????????????查看评论

标签: delphi delphi-xe2 rtti delphi-xe3


【解决方案1】:
Result := Result + '|' + GetFieldValue<T>(Addr(piclObject),loclRecordField);

应该做的工作。

【讨论】:

    【解决方案2】:

    对不起,我的英语不好。

    @bummi 的答案有效但不正确。

    这取决于使用情况。

    如果你使用下一个代码一切正常:

    var
      losDummyRecord : tysDummyRecord;
    begin
      FillChar(losDummyRecord, SizeOf(tysDummyRecord), #0);
      losDummyRecord.Header.MessageCode := 5000;
      losDummyRecord.Header.MessageLength := 54433;
      losDummyRecord.BotAmount := 19.45;
      losDummyRecord.SoldAmount := 34.22;
      losDummyRecord.SoldQty := 102;
      losDummyRecord.BotQty := 334;
      losDummyRecord.Tailer := @losDummyRecord.Header;
    
      ShowMessage(TclDummy.ParseAndReturnString<tysDummyRecord>(losDummyRecord));
    

    但如果您使用例如此代码,解析将无法正常工作:

    var
      losDummyRecord : tysDummyRecord;
      ExternalHeaderVar: tysDummyHeader;
    begin
      ExternalHeaderVar.MessageCode := 23;
      ExternalHeaderVar.MessageLength := 25;
    
      FillChar(losDummyRecord, SizeOf(tysDummyRecord), #0);
      losDummyRecord.Header.MessageCode := 5000;
      losDummyRecord.Header.MessageLength := 54433;
      losDummyRecord.BotAmount := 19.45;
      losDummyRecord.SoldAmount := 34.22;
      losDummyRecord.SoldQty := 102;
      losDummyRecord.BotQty := 334;
      losDummyRecord.Tailer := @ExternalHeaderVar;
    
      ShowMessage(TclDummy.ParseAndReturnString<tysDummyRecord>(losDummyRecord));
    

    解决方案很简单,在两种情况下都能很好地工作,并且可以防止将来使用时出现意外错误:

          tkPointer:
          begin
            losPointerType := loclField.FieldType as TRttiPointerType;
    
            // Check only record type pointers.
            if losPointerType.ReferredType.TypeKind = tkRecord then
            begin
              losValue := loclField.GetValue(Addr(piclObject));
              if (not losValue.IsEmpty) then
              begin
                losValue.ExtractRawDataNoCopy(@NativeIntVar);
                for loclRecordField in losPointerType.ReferredType.GetFields do
                begin
                  Result := Result + '|' + GetFieldValue<T>(Pointer(NativeIntVar),loclRecordField);
                end;
              end;
            end;
          end; // tkPointer
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-05-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-01
      • 1970-01-01
      相关资源
      最近更新 更多