如何在delphi中反序列化子属性?

时间:2012-06-30 12:48:04

标签: delphi serialization

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

  

异常类EPropertyConvertError,消息'Invalid property type:TSomething'

因为我刚刚学习这个,所以我不确定是什么问题。我确实有一些猜测,其中一个可能是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;

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

2 个答案:

答案 0 :(得分:3)

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

Self.SetSubComponent(True);

最后,由于你的类是一个TComponent,你将不再需要从 delphi.about 中获取的东西,因为TComponent可以通过使用 WriteComponent / ReadComponent

选择正确的后代时,您会发现这个过程比较简单。这里的选择是逻辑:如果你想序列化,那么使用TComponent。

答案 1 :(得分: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的写入方法将如下所示:

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,你也会在你的例子中使用类似的方法。

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