我可以创建一个构造函数来反序列化对象的字符串版本吗?
我正在使用 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;
I'm serializing and deserializing an object (TComponent descendant) using the example in the ComponentToString section in the Delphi help file. This is so I can store the object in a VARCHAR field in the database.
When I need to instantiate a new instance of my class from a string stored in the database, can I do that using a constructor of the form CreateFromString(AOwner: TComponent; AData: String)
? Or do I have to use a non-class method that returns an instance of my component class?
If I can use the constructor version, how to I "map" the return value of ReadComponent to the "self" that is being created by the constructor?
Here's the deserialization example from the help file:
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;
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
一般来说,是的,您可以使构造函数反序列化字符串并使用该信息来初始化新实例。一个简单的例子是具有单个 Integer 字段的类。将字符串传递给构造函数,让构造函数调用
StrToInt
并使用结果初始化字段。但是,如果您用于反序列化的唯一函数也是创建实例的函数,那么您就不能从构造函数中使用该函数,因为当您只需要一个实例时,您最终会得到两个实例。构造函数不可能说:“没关系;毕竟不要构造实例。我已经在其他地方得到了一个实例。”
但是,这不是您所处的情况。您应该知道,
TStream.ReadComponent
允许您自己创建实例。仅当您尚未为其提供要使用的实例时,它才会实例化该类。您应该能够像这样编写构造函数:我们将由
Self
指定的当前对象传递给ReadComponent
。流将忽略存储在流中的类名,并假定当前对象属于正确的类。In general, yes, you can make a constructor deserialize a string and use that information to initialize the new instance. A trivial example of that would be a class with a single
Integer
field. Pass a string to the constructor and have the constructor callStrToInt
and initialize the field with the result.But if the only function you have for deserialization is one that also creates the instance, then you cannot use that from the constructor because then you'll end up with two instances when you only wanted one. There's no way for a constructor to say, "Never mind; don't construct an instance after all. I already got one somewhere else."
However, that's not the situation you're in. As you should know,
TStream.ReadComponent
allows you to create the instance yourself. It only instantiates the class if you haven't already given it an instance to use. You should be able to write your constructor like this:There we're passing the current object, designated by
Self
, toReadComponent
. The stream will ignore the class name stored in the stream and assume that the current object is of the correct class.您可以通过
类
(静态)方法来完成此操作,但不能通过构造函数
来完成此操作。Delphis 的构造函数由编译器内在刚刚创建的实例上调用,该实例已经部分初始化(它是所需的类,并且实例/字段存储已清零)。
如果你查看
TStream.ReadComponent
的源码,你会发现组件的真实类首先从源流中读取,然后构造一个空实例并由RTTI从流中填充,然后作为结果返回。这意味着:要使用
TStream.ReadComponent
,您需要通过RegisterClass
将您的类注册到Delphis的流系统。You can do this by a
class
(static) method, but not via aconstructor
.Delphis' constructors are called by compiler intrinsic on the just-created instance, which is already partially initialized (it's of the desired class and instance/field storage is zeroed-out).
If you see the source of
TStream.ReadComponent
, you'll find that the components' real class is read from the source stream at first, then an empty instance is constructed and filled by RTTI from the stream and returned as the result. Which means:To use
TStream.ReadComponent
, you'll need to register your class to Delphis' streaming system viaRegisterClass
.使用静态
类函数
而不是构造函数
:AOwner部分可能是个问题,因为TStream.ReadComponent没有所有者的参数。
关于该问题还有另一个问题:
如何指定从 Delphi TStream 读取的组件的所有者?
编辑: 我已经更新了代码示例以包含所有者。
请注意,插入到所有者的组件列表中需要为要插入的组件提供唯一的或空的
Name
。Use a static
class function
instead of aconstructor
:The AOwner part could be a problem though, since TStream.ReadComponent has no parameter for the owner.
There is another so question about that problem:
How can I specify the Owner of component read from a Delphi TStream?
Edit: I've updated the code sample to include the owner, too.
Note that inserting into the component list of the owner requires a unique or empty
Name
for the component that is being inserted.