动态结构的大小

| (希望)这将很快得到解决,这是我的问题: 我有一个结构
PMacro = ^TMacro;
  TMacro = class
    Hotkey: Integer;
    Command: String;
    CTRLMode: boolean;
    RepeatInterval: integer;

    constructor Create(Hotkey: Integer; Command: String; CTRLMode: boolean; RepeatInterval: integer); overload;
    constructor Create; overload;
    procedure Execute;
  end;
我需要获取它的大小(通过TFileStream保存)。此类的实例存储在其他地方的列表中,这是我的保存例程:
Stream:=TFileStream.Create(FileName,fmCreate or fmOpenWrite);
  for i := 0 to Macros.Count-1 do
  begin
    Macro:=TMacro(Macros[i]);
    Size:=sizeof(Macro);
    Stream.Write(size,SizeOf(integer));
    Stream.Write(Macro,sizeof(Macro));
  end;
SizeOf(Macro)返回4bytes,这将是指针,但是我需要特定实例占用的实际空间。我想到的第一件事是获得ѭ2,因为它是一个动态结构,可返回其指针的大小。但这将意味着要有“ѭ3”之类的字眼,但这对于进一步扩展TMacro结构是不利的。 那么,有没有办法获取包含动态类型的结构的大小? 谢谢你的回答     
已邀请:
如果要获取TMacro的大小,请调用InstanceSize方法。但这并不能帮助您将其块写入流中,它也不会更改为包括字符串的大小,因为字符串是引用类型。 您不能像这样阻塞您的TMacro结构。首先,它是一个类,而不是记录,这意味着它包含一个您不想保存的“ magic”字段(如果您使用的是Delphi 2009或更高版本,则包含两个字段) 。其次,即使它是一条记录,它仍然包含引用类型(字符串),因此数据不会内联存储在TMacro中。它存储在堆中,必须单独访问。 如果需要实现序列化,则可以采用几种不同的方法。创建一对这样的方法:
procedure Load(savefile: TStream); //can also be implemented as a constructor
procedure Save(savefile: TStream);
然后将它们实现为一对一地读取/写入每个字段,或者将其与RTTI一起使用某种通用序列化器。这在Delphi 2010中更容易编写,因为它具有更广泛的RTTI功能集。     
由于Delphi对象是引用类型,因此“ 5”将返回引用的大小,该大小与指针的大小相同,在当前的Delphi版本中为4字节。 如果记录中的数据是值类型,则“ 5”将返回内容的大小。 但是,由于您的结构包含托管类型(即字符串),因此您不能像这样简单地将其保存在一个大的glob中。您需要对字符串进行特殊处理。 如果我是你,我将逐项保存信息。特别是,这使您可以控制诸如对齐之类的问题,并可以满足版本控制的需要。您可以轻松地编写自己的非常基本的代码来执行此操作。但是,在以下情况下,您可能需要考虑使用第三方框架: 有很多字段要保留,单独处理它们将导致非常费力的代码。 您希望为文件格式的版本化提供一些灵活性。例如,当您添加新字段,更改现有字段的含义等时,您可能希望考虑软件的未来版本中会发生什么。     
如果希望SizeOf给出记录的大小,然后可以将其二进制持久化,则可以(尽管我个人不建议二进制记录持久化)使用RECORD类型。 我认为,要在这个问题上弄清楚,不仅需要戴维的答案和梅森,而且还需要推论原则: 如果要确定SizeOf(RECORDTYPE),请首先使用RECORD(而不是Class),然后使用100%值类型(例如Char数组(不是String))会生成Binary Persistable记录:
  type
    TMyCharType = UnicodeChar; // or AnsiChar. Your choice.  
    PMacro = ^TMacro;
    TMacro = record
      Hotkey: Integer;
      Command: Array [0..1000] of TMyCharType;  
      CTRLMode: Boolean;
      RepeatInterval: integer;
    end;
就样式而言,我倾向于使用基于类的系统,该系统使用比基于记录的二进制存储更高级的持久性样式。但是,如果您要这样做,请使用RECORD,而不是Class,也不要使用String。 此外,请注意,在代码示例中,如果TMacro是一个类,则PMacro = ^ TMacro确实比错误更糟糕。 (除非您真的要进行某种双指针间接访问。) TMacro(引用类型)已经是按引用的,因此不需要获取它们的地址,因为它们是在TMacro类型的变量(如果是类)之间作为指针在内部传递的。因此,您确实确实需要对代码中的记录类型和值类型有一些了解。     

要回复问题请先登录注册