(delphi11最新学习资料) Object Pascal 学习笔记---第10章第2节(published访问说明符)

news/2024/9/24 4:58:05/

10.2 published访问说明符

​ 除了 public、protected 和 private 访问指令(以及不太常用的strict private 和strict protected)之外,Object Pascal 语言还有一个非常特别的访问指令,叫做 published。published属性(或字段或方法)不仅可以像public属性一样在运行时可用,而且还能生成可查询的扩展运行时信息(extended RTTI)。

​ 事实上,在编译型语言中,编译后的符号由编译器处理并且在测试应用程序时调试器可以使用,但在运行时一般不会留下这些符号。换句话说(至少在早期的 Object Pascal 语言中是这样),如果一个类有一个名为 Name 的属性,你可以在代码中使用它来与类交互,但这种交互会被转换成数字地址,而源代码级别的标识符概念在运行时就不存在了,这意味着没有办法找出一个类是否有与给定字符串(如 “Name”)相匹配的属性标识符。

**注意:**Java 和 C# 语言都是采用了复杂虚拟执行环境(虚拟机)的编译型语言,因此,它们通过一种称为反射的概念拥有大量的运行时信息。Object Pascal 语言早在其他编译语言之前就有了基本的反射(通过published关键字),而之后随着语言的演变又引入了更多的反射或者说扩展的RTTI。本章将探讨与published关键字相关的基本 RTTI,第 16 章将探讨扩展反射。

​ 为什么需要这些关于类的额外信息呢?这些信息是Object Pascal库所依靠的组件模型和可视化编程模型的基础之一。其中一些信息在开发环境中进行设计时使用,以填充“对象检视器”(Object Inspector)中组件提供的属性列表。这不是一个硬编码的列表,而是通过运行时检查编译后的代码中包含的额外运行时类型信息(RTTI)数据生成的。

​ 另一个例子,可能有点复杂,现在不太适合深入讨论的是创建FMX和DFM文件以及任何附带的可视化窗体背后的流式传输机制。流式传输将仅在第18章中介绍,因为它更多地属于运行时库而不是核心语言。

​ 总结这一概念:当您编写供自己或其他人在开发环境中使用的组件时,使用published关键字是重要的。通常,组件的published部分仅包含属性,但是窗体类还会使用published字段和方法,这些将在稍后介绍。

10.2.1 设计时属性

​ 在本章的前面部分,我们已经了解到属性在类的数据封装中扮演着重要角色。它们还在启用可视化开发模型方面起着基础性作用。事实上,您可以编写一个组件类,将其提供给开发环境,通过将其添加到窗体或类似的设计界面来创建对象,并使用“对象检视器”与其属性进行交互——这是可视化编程环境提供的工具,让您能够访问属性。并非所有属性都可以在这种情况下使用,只有那些在组件类中标记为"published"的属性才能够。这就是为什么Object Pascal程序员区分设计时属性运行时属性

​ 设计时属性是在类声明的"published"部分中声明的,可以在IDE中以及在代码中使用。在类的"public"部分中声明的任何其他属性都不可在设计时使用,只能在代码中使用,通常被称为仅在运行时可用的属性。

​ 换句话说,在设计时,您可以使用“对象检视器”查看并更改published属性的值。在运行时,您可以通过完全一样的方式在代码中读取值或写入值的方式访问另一个类的任何public或published属性。

​ 并非所有类都有属性。属性存在于组件和TPersistent类的其他子类中,因为属性通常可以被流式传输并保存到文件中。事实上,窗体文件只不过是窗体上组件的published属性的集合。

​ 更准确地说,要在一个类中支持published节(section),你不需要继TPersistent 类,但你需要使用$M编译器指令编译这个类。每一个使用该指令编译的类,或者从使用该指令编译的类派生出来的类,都支持published节。由于 TPersistent 是使用此设置编译的,那么其任何派生类都支持此功能。

注意 下面关于默认可见性和自动 RTTI 的两节将进一步介绍$M 指令和published关键字的更多信息。

10.2.2 published属性与窗体

​ 当IDE(集成开发环境)生成一个表单时,它会把表单上组件和方法的定义放在类的初始部分,也就是public和private关键词之前。这些初始部分的字段和方法就是已发布的属性。

​ 尽管published属性是全局可见的,但这并不意味着进行全局访问是一个好主意。这意味着您必须特别注意您正在访问的全局属性(正如在前面关于向表单添加属性的部分所讨论的)。此外,当在组件类的元素之前指定显式访问指令时,默认访问级别是published。

注意 更准确地说,只有当类是在使用$M+编译器指令的情况下编译的,或者是从使用$M+编译器指令编译的类派生的,published才是默认关键字。由于TPersistent类中使用了该指令,因此库的大多数类和所有组件类默认是published。然而,非组件类(如TStream和TList)是在使用$Mand指令的情况下编译的,它们默认是public可见性。

​ 这里是一个例子:

typeTForm1 = class(TForm)Memo1: TMemo;BtnTest: TButton;

​ 分配给任何事件的方法都应该是published方法,窗体中与您的组件相对应的字段应该也是published,以便能够自动与窗体文件中描述的对象连接并随着窗体一起创建。

​ 只有窗体声明初始published部分中的组件和方法才会出现在对象检查器中(在窗体组件列表中或当您选择事件下拉列表时显示的可用方法列表)。

​ 为什么类的组件应该使用published段进行声明,而它们可以是私有的并更好地遵循OOP封装规则?原因在于这些组件是通过读取其流式表示而创建的,但一旦创建,就需要分配给相应的窗体字段。

​ 这是通过RTTI完成的,RTTI由published字段生成。

注意,从技术上讲,并不是真的强制要求为组件使用published字段。通过将组件设为私有,可以让代码更加符合面向对象设计原则。然而,这样做需要额外的运行时代码。我将在本章的最后一节“RAD和OOP”中对此进行进一步解释。

10.2.3 RTTI自动生成

​ Object Pascal编译器另一个特殊的行为是,如果你在一个不是从TPersistent类继承的类中添加published关键字,编译器将自动启用RTTI生成,自动添加{$M+}编译指令。假设你有这样的一个类:

typeTMyTestClass = classprivateFValue: Integer;procedure SetValue(const Value: Integer);publishedproperty Value: Integer read FValue write SetValue;end;

​ 编译器将发出如下警告:

[dcc32 Warning] AutoRTTIForm.pas(27): W1055 PUBLISHED caused RTTI ($M+)
to be added to type 'TMyTestClass'

​ 幕后所发生的是,编译器会自动在代码中注入{$M+}指令,正如你在AutoRTTI示例中所看到的那样,该示例包含了上面的代码。在这个程序中,你可以编写以下代码,该代码可以动态地访问属性(使用老式的System.TypInfo单元):

usesTypInfo;procedure TFormAutoRtti.BtnTestClick(Sender: TObject);
varTest1: TMyTestClass;
beginTest1 := TMyTestClass.Create;tryTest1.Value := 22;Memo1.Lines.Add(GetPropValue(Test1, 'Value'));finallyTest1.Free;end;
end;

注意 尽管我偶尔会使用TypInfo单元及其定义的GetPropValue等函数,但RTTI访问的真正威力是由更现代的RTTI单元及其对反射的大量支持提供的。考虑到这是一个相当复杂的话题,我觉得应该单独为它写一章,并且还要区分现代Object Pascal支持的两种RTTI风格。


http://www.ppmy.cn/news/1437145.html

相关文章

Java毕业设计 基于SpringBoot vue养老院管理系统 微信小程序

Java毕业设计 基于SpringBoot vue养老院管理系统 微信小程序 SpringBoot 养老院管理系统 功能介绍 小程序 护工登录注册 忘记密码 护工信息维护 首页 图片轮播 床位调动申请 床位展示 床位详情 床位分配 房间展示 公告信息 公告详情 健康信息 请假申请 离职申请 后台管理 登…

1.基于Springboot对SpringEvent初步封装

一:前置知识 Spring Event是Spring框架提供的一种事件机制,用于处理组件之间的通信。在复杂的系统中,模块或组件之间的通信是必不可少的。Spring Event可以用于以下场景: 1.系统间解耦:模块或组件之间通过事件进行通…

阿里云直播推流和播流地址的生成方法PHP

最近在用阿里云的直播SDK在进行直播功能的开发,整体来说磕磕绊绊,因为里面有好多的东西,一时半会的搞不定,但是工期又有期限,所以天天熬夜,程序员真心不容易,废话不多说,今天分享这个主要就是来…

设计模式:接口隔离原则(Interface Segregation Principle,ISP)介绍

接口隔离原则(Interface Segregation Principle,ISP)是面向对象设计原则之一,它强调一个类不应该依赖于它不需要的接口。接口隔离原则的核心思想是将大的接口拆分成更小的、更具体的接口,客户端应该仅依赖于它们需要使…

Sulley入门教学——简介、安装(Win7、VMware)

1、简介 Sulley 是由 Pedram Amini 和 Aaron Portnoy 开发的开源工具。它以 Python 编写,可以轻松地在不同平台上部署和使用。Sulley 提供了一个灵活且功能强大的框架,允许用户定义协议消息的结构、字段类型、边界条件和模糊测试策略。用户可以使用 Sul…

频裂变加群推广强制分享引流源码

视频裂变加群推广强制分享引流源码,用户达到观看次数后需要分享给好友或者群,好友必须点击推广链接后才会增加观看次数。 引导用户转发QV分享,达到快速裂变引流的效果! 视频裂变推广程序,强制分享链接,引导用户转发,…

深入解析实时数仓Doris:介绍、架构剖析、应用场景与数据划分细节

码到三十五 : 个人主页 心中有诗画,指尖舞代码,目光览世界,步履越千山,人间尽值得 ! Doris是一款高性能、开源的实时分析数据仓库,旨在为用户提供毫秒级查询响应、高并发、高可用以及易于扩展的OLAP解决方…

LeetCode53. 最大子数组和

LeetCode53. 最大子数组和 解题思路dp 代码 /* 数组长度n 9,连续的区间 那区间长度为1的区间数量是&#xff0c;9个 区间长度为2的区间数量是8个 区间长度为3的连续的区间数量为7个 .... 区间长度为9的区间数量为1个 */ class Solution { public:int maxSubArray(vector<…