Delphi2010 如何遍历 RTTI 中的记录类型?

3
type
 myrec = record
 id:dWord;
 name:array[0..31] of  WideChar;
 three:dword;
 count:dword;
 ShuXing:Single;
 ShuXing2:dword;
 ShuXing3:dWORD;

  end;

var
  Form1: TForm1;
  mystr:TMemoryStream;
  nowmyrec:myrec;

implementation
 USES Rtti;
{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);


var
  rttiContext: TRttiContext;
  rttiType: TRttiType;
  fields: TArray<TRttiField>;
  item: myrec;
  i:word;
begin
mystr:=TMemoryStream.Create;
mystr.LoadFromFile(ExtractFilePath(Application.exename)+'1.data');
mystr.Position:=20;
mystr.readbuffer(nowmyRec,88);




 rttiType := rttiContext.GetType(TypeInfo(myRec));
  fields := rttiType.GetFields;
   for i := low(fields) to high(fields) do
   begin
Memo1.Lines.Add(fields[i].GetValue(@nowmyRec).ToString );


   end;

end;

end.

myrec.name是中文字符,长度为64字节,我无法将myrec.name读入备忘录,请帮助我!

1个回答

2

我是在Delphi 2010上工作的,发现你的代码存在一些问题。首先,我无法使用字符数组的内联声明使RTTI方法正常工作。我将其更改为:

type
  TCharArray = array[0..31] of WideChar;
  TRec = record
    id:dWord;
    name:TCharArray;
  end;

如果你像之前那样内联声明数组,调用GetValue将会触发AV(访问冲突)。这个问题在XE版本中可能已经被修复了,或者很有可能是我错误地使用了RTTI。
其次,你需要对数组进行特殊处理,而不是标量值:
procedure Main;
var
  i, j: Integer;
  rec: TRec;
  rttiContext: TRttiContext;
  rttiType: TRttiType;
  fields: TArray<TRttiField>;
  val: TValue;
  s: string;
begin
  rec.id := 1;
  rec.name := 'Hello Stack Overflow';

  rttiType := rttiContext.GetType(TypeInfo(TRec));
  fields := rttiType.GetFields;
  for i := low(fields) to high(fields) do begin
    val := fields[i].GetValue(@rec);
    if val.IsArray then begin
      s := '';
      for j := 0 to val.GetArrayLength-1 do begin
        s := s+val.GetArrayElement(j).ToString;
      end;
      Writeln(s);
    end else begin
      Writeln(val.ToString);
    end;
  end;
end;

输出:

1
Hello Stack Overflow

这显然不是生产代码,但至少可以让你重新上路!

顺便说一句,这是我第一次看新的RTTI功能。它看起来相当不错!


我正在读取十六进制数据,必须使用TStream!"rec.name := 'Hello Stack Overflow':不能适用于我。 - babaloveyou
@baba,你的问题出在RTTI上而不是流代码上。由于我手头没有你的二进制输入数据,所以我用自己的数据填充了记录,只是为了证明RTTI代码可以工作。请随意填充你自己的记录。 - David Heffernan
@baba 为什么不按照我的建议更改记录的定义呢?这样就可以防止在第二次调用GetValue时出现AV错误。然后将调用 fields[i].GetValue(@nowmyRec).ToString 的代码替换为我的版本,该版本添加了 IsArray。然后它就可以正常工作了。 - David Heffernan
@baba感谢接受。我相信您现在很满意。顺便说一下,您现在有足够的声望来投票了!! ;-) - David Heffernan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接