4

从两天前开始,我开始从头开始制作我自己的简单类,源自TObject,没什么特别的。我还需要在文件中写入/读取它们,所以经过一番搜索,因为我还没有学习序列化的所有细节,也没有完全掌握它们,所以我从这里借用了序列化方法。当我测试它时,它工作得很好。然后我添加了另一个类作为属性(这就是我说 sup-property 时所指的:类的属性,它是我的类中的一个属性......这很令人困惑,它需要一个正确的名称),遵循中的建议这个所以关于如何实际做到这一点的问题。现在写入文件似乎不会引发任何错误,然后我又不确定子属性是否正确写入或者它只是垃圾。然而,读回来确实会导致

带有消息“无效属性类型:TSomething”的异常类 EPropertyConvertError

由于我只是在学习这个,我不确定是什么问题。我确实有一些疯狂的猜测,其中之一是TSomething = Class可能必须拥有自己的序列化方法?在那种情况下,这将如何运作(因为即使我不相信这个假设)?另一个是我从delphi.about.com借来的代码不能处理这些类型的属性?如果是这样,我该如何改进它?如果我的猜测都不是正确的,那么如何做到这一点呢?(而且我正在使用 DelphiXE2。)

根据要求编码:

TSomething = Class
protected
  fNumber: integer;
  fLine: string;
public
  procedure Assign(Source: TObject);
published
  property Number: integer read fNumber write fNumber;
  property Line: string read fLine write fLine;
End;

TOther = Class
public
  procedure LoadFromStream(const Stream: TMemoryStream);
  procedure SaveToStream(const Stream: TMemoryStream);
  constructor Create; virtual;
  destructor Destroy; override;
protected
  fSomething: TSomething;
  procedure SetfSmth(AValue: TSomething);
published
  property Something: TSomething read fSomething write SetfSomething;
end;

方法的实现是从上面提供的两个链接中借用的,我认为没有必要重新输入,除非要求。

4

2 回答 2

3

要序列化 ​​TSomething,它必须是子组件。为此,您必须更改一件事:不要从 TObject 派生这两个类,而是从 TComponent 派生。然后在你调用的 TSomething 构造函数中

Self.SetSubComponent(True);

最后,由于您的类是 TComponent,您将不再需要从delphi.about中获取的内容,因为可以使用WriteComponent / ReadComponent 在 TStream 中直接序列化TComponent

您会发现选择正确的后代时该过程更容易。这里的选择是逻辑:如果你想序列化然后使用 TComponent。

于 2012-06-30T15:23:39.777 回答
1

我认为你应该跟进你的想法,给它自己的 TSomething 类序列化方法。

下面是一个示例,使用 XML 进行序列化:

TSomething = class(TPersistent)
protected
  FNumber: Integer;
  FLine: String;
public
  procedure WriteToXmlNode(XmlNode: IXmlNode);
  procedure ReadFromXmlNode(XmlNode: IXmlNode);
published
  property Number: Integer read FNumber write FNumber;
  property Line: String read FLine write FLine;
end;

TOther = class(TPersistent)
protected
  FSomething: TSomething;
public
  procedure WriteToXmlNode(XmlNode: IXmlNode);
  procedure ReadFromXmlNode(XmlNode: IXmlNode);
published
  property Something: TSomething read FSomething write FSomething;
end;

换句话说,让每个类都知道如何将自己序列化为 XML。

TOther 的 write 方法将如下所示:

procedure TOther.WriteToXmlNode(XmlNode: IXmlNode)
var
  ChildNode: IXmlNode;
begin
  // Write something
  ChildNode := XmlNode.AddChild('Something');
  Something.WriteToXmlNode(ChildNode);       
end;

读取方法将如下所示:

procedure TOther.ReadFromXmlNode(XmlNode: IXmlNode)
var
  ChildNode: IXmlNode;
begin
  // Read
  ChildNode := XmlNode.ChildNodes.First;
  while Assigned(ChildNode) do
  begin
    // Read something
    if ChildNode.NodeName = 'Something' then
      Something.ReadFromXmlNode(ChildNode);

    // Next child node
    ChildNode := ChildNode.NextSibling;
  end;
end;

这就是它的一般要点。

我认为您将在示例中使用类似的方法,即使您不选择序列化为 XML。

编辑:在你的问题中你想要什么有点不清楚。如果您正在编写组件,并且希望在设计时使用它们时正确序列化组件的属性,那么这不是要走的路。我描述的方法是在运行时序列化任意对象。

于 2012-06-30T16:21:36.520 回答