我正在使用Delphi帮助文件的ComponentToString部分中的示例对对象(TComponent后代)进行序列化和反序列化。这样我就可以将对象存储在数据库的VARCHAR字段中。
当我需要从存储在数据库中的字符串实例化我的类的新实例时,我可以使用CreateFromString(AOwner: TComponent; AData: String)
形式的构造函数来实现吗?或者我是否必须使用返回组件类实例的非类方法?
如果我可以使用构造函数版本,如何将ReadComponent的返回值“映射”到构造函数创建的“self”?
以下是帮助文件中的反序列化示例:
function StringToComponentProc(Value: string): TComponent;
var
StrStream:TStringStream;
BinStream: TMemoryStream;
begin
StrStream := TStringStream.Create(Value);
try
BinStream := TMemoryStream.Create;
try
ObjectTextToBinary(StrStream, BinStream);
BinStream.Seek(0, soFromBeginning);
Result:= BinStream.ReadComponent(nil);
finally
BinStream.Free;
end;
finally
StrStream.Free;
end;
end;
答案 0 :(得分:6)
通常,是的,您可以使构造函数反序列化字符串并使用该信息初始化新实例。一个简单的例子就是具有单个Integer
字段的类。将一个字符串传递给构造函数,并让构造函数调用StrToInt
并使用结果初始化该字段。
但是如果你反序列化的唯一函数是也创建实例的函数,那么就不能在构造函数中使用它,因为当你只需要一个实例时,你最终会得到两个实例。构造函数没有办法说,“没关系;毕竟不要构造一个实例。我已经在其他地方找到了一个。”
但是,这不是你所处的情况。正如你所知,TStream.ReadComponent
允许你自己创建实例。如果您尚未为其提供要使用的实例,则它仅实例化该类。您应该能够像这样编写构造函数:
constructor TLarryComponent.CreateFromString(const AData: string);
var
StrStream, BinStream: TStream;
begin
Create(nil);
StrStream := TStringStream.Create(AData);
try
BinStream := TMemoryStream.Create;
try
ObjectTextToBinary(StrStream, BinStream);
BinStream.Position := 0;
BinStream.ReadComponent(Self);
finally
BinStream.Free;
end;
finally
StrStream.Free;
end;
end;
我们将Self
指定的当前对象传递给ReadComponent
。流将忽略存储在流中的类名,并假定当前对象具有正确的类。
答案 1 :(得分:3)
使用静态class function
代替constructor
:
type
TYourClass = class(TComponent)
public
class function CreateFromString(AOwner: TComponent; AData: String): TYourClass; static;
end;
implementation
class function TYourClass.CreateFromString(AOwner: TComponent; AData: String): TYourClass;
begin
Result := (StringToComponentProc(AData) as TYourClass);
if AOwner <> nil then
AOwner.InsertComponent(Result);
end;
但是,AOwner部分可能是个问题,因为TStream.ReadComponent没有所有者的参数。
关于这个问题还有另外一个问题:
How can I specify the Owner of component read from a Delphi TStream?
修改:我已更新代码示例以包含所有者。
请注意,插入所有者的组件列表需要为要插入的组件提供唯一或空Name
。
答案 2 :(得分:3)
您可以使用class
(静态)方法执行此操作,但不通过constructor
执行此操作。
Delphis的构造函数由刚创建的实例上的编译器内部调用,该实例已经部分初始化(它是所需的类,实例/字段存储被清零)。
如果你看到TStream.ReadComponent
的来源,你会发现首先从源流中读取组件的真实类,然后构造一个空实例并由流中的RTTI填充并返回为结果。这意味着:
要使用TStream.ReadComponent
,您需要通过RegisterClass
将您的课程注册到Delphis的流媒体系统。