Delphi 的RTTI机制-3
====================================
⊙TPersistent.DefineProperties
虚方法
====================================
DefineProperties
虚方法用于元件设计者自定义非 published
属性的存储和读取方法。 TPersistent
定义的该方法是个空方法,到 TComponent
之后被重载。
下面以
TComponent
为例说明该方法的用法:
DefineProperties
调用 Filer.DefineProperty
或 DefineBinaryProperty
方法读写流中属性值。
TReader.DefineProperty
方法检查传入的属性名称是否与当前流中读到的属性名称相同,如果相同,则调用传入的 ReadData
方法读取数据,并设置 FPropName
为空,用以通知 ReadProperty
已经完成读属性值的工作,否则将会触发异常。
TWriter.DefineProperty
根据 HasData
参数决定是否需要写属性值。
如果
Filer.Ancestor
不是 nil,表示当前正在读取的元件继承自表单父类中的元件,元件设计者可以根据
Ancestor
判断是否需要写属性至流中。例如:当前元件的属性值与原表单类中的元件属性值相同的时候,可以不写入(通常是这样设计)。
ReadData、WriteData
参数是从 Filer
对象中读写数据的方法地址,它们的类型是:
比如:
对于二进制格式的属性值,可以使用
TFiler.DefineBinaryProperty
方法读写:
Stream
参数是从流中读出的二进制数据或要写入二进制数据的流对象句柄。
注意:自己定义属性的读写方法时要记得调用
inherited
DefineProperties(Filer),否则祖先类的自定义属性读写操作不会进行。TControl
是个例外,因为它已经定义了 published Left
和 Top
属性。
===============================================================================
⊙TReader.ReadComponent
方法
===============================================================================
ReadComponent
的执行过程与 ReadRootComponent
的过程很相似,它根据流中的信息使用FindComponentClass
方法找到元件类在内存中的地址,然后调用该元件类的构造函数创建对象,接下来调用新建对象的 ReadState -> TReader.ReadData ->
ReadDataInner -> TReader.ReadProperty,重复
ReadRootComponent
的过程。
TReader.ReadComponent
和 TComponent.ReadState
形成递归调用过程,把表单上嵌套的元件创建出来。
===============================================================================
⊙TReader.ReadValue / TReader.NextValue
系列方法
===============================================================================
ReadValue
方法从流中读出一个TValueType
类型的数据,它主要由其它的方法调用。
TValueType
中只有 vaList
比较特殊,它表示后面的数据是一个属性值系列,以 vaNull
结束。其余的枚举值的都是指属性的数据类型或值。
NextValue
方法调用 ReadValue
返回流中下一个数据的类型,然后将流指针回退至读数据之前。通常用于检测流中下一个数据的类型。
CheckValue
方法调用 ReadValue
检查下一个数据类型是否是指定的类型,如果不是则触发异常。
ReadListBegin
方法检查下一个数据是否是 vaList,它调用
CheckValue
方法。
ReadListEnd
方法检查下一个数据是否是 vaNull,它调用
CheckValue
方法。
SkipValue
方法使用 ReadValue
获得下一个数据的类型,然后将流指针跳过这个数据。
===============================================================================
⊙TReader.ReadStr
方法
===============================================================================
ReadStr
方法读出流中的短字符串,TReader
内部使用它读取属性名称等字符串,元件设计者应该使用 ReadString
函数读取属性值。
===============================================================================
⊙TReader.ReadInteger / ReadString /
ReadBoolean
系列方法
===============================================================================
TReader
有一系列读取属性值的函数,可供元件设计者使用。
===============================================================================
⊙TReader.Read
方法
===============================================================================
TReader
中所有的数据都是通过TReader.Read
方法读取的。TReader
不直接调用 TStream
的读方法是因为 TReader
的读数据操作很频繁,它自己建立了一个缓冲区(4K),只有当缓冲区中的数据读完之后才会调用
TStream.Read
再读入下一段数据,这样可以极大地加快读取速度。Read
是个汇编函数,编写得很巧妙,它的代码及注释如下:
procedure TReader.Read(var Buf;
Count: Longint); assembler;
asm
@@1:
@@2:
@@3:
@@6:
end;
===============================================================================
⊙ObjectBinaryToText / ObjectTextToBinary
函数
===============================================================================
Classes.pas
中的 ObjectBinaryToText
和 ObjectTextToBinary
函数用于把对象属性信息转换为文本形式或二进制形式。
新建一个项目,在表单上放置一个
TMemo
控件,然后执行以下代码,就能明白这两个函数的作用了。在Delphi
的 IDE
中,将 DFM
文件进行二进制和文本方式的转换应该是通过这两个函数进行的。
上面的两个函数还有一对增强版本,它们增加了对资源文件格式的转换,实际上也是调用了上面的函数:
Delphi
编译程序生成应用程序的资源数据段,应该是用ObjectTextToResource
函数进行的。
注:ObjectTextToBinary
调用了
TParser
对象进行字符串解析工作。