跟着老侯玩编程 跟着老侯玩编程
首页
  • 基础语法
  • 设计模式
  • 基础语法
  • 课程目录
  • 码农宝典
网盘 (opens new window)
留言
首页
  • 基础语法
  • 设计模式
  • 基础语法
  • 课程目录
  • 码农宝典
网盘 (opens new window)
留言
  • 基础语法

    • 单元文件
    • 变量和常量
    • 内联变量
    • 基本数据类型
    • 复合数据类型
    • 语句(选择语句)
    • 语句(循环语句)
    • 数组
    • 初识例程
    • 初识面向对象
    • 属性Property
    • 面向对象的方法
    • 指针
    • 接口
    • 匿名函数和委托实现
    • 多态
    • 字符串详解
    • 异常处理
    • 反射机制
      • 运行期类型信息概述
      • 初识反射
    • 泛型容器
    • JSON
    • 文件操作
    • Dll创建并调用
    • DLL初始化和退出处理
    • Package
    • 理解消息循环
    • VCL与Windows消息
    • 钩子原理
    • 进程通讯-内存映像
    • 多线程开篇
    • 线程控制
    • 线程同步
  • 设计模式

    • 单例模式
    • 单例模式二
    • 策略模式
    • 简单工厂模式
    • 建造者模式
    • 原型模式
    • 模板方法模式
    • 状态模式
    • 迭代器模式
    • 解释器模式
    • 责任链模式
    • 中介者模式
    • 备忘录模式
    • 命令模式
    • 观察者模式
    • 访问者模式
    • 适配器模式
    • 桥接模式
  • Delphi
  • 基础语法
舞动的代码
2022-05-05

反射机制

在Java中存在着一种强大的功能就是反射,所以我在考虑Delphi出来这么多年了,难道没有支持反射机制吗?经过翻山越岭的一顿搜索终于找到了反射的身影!

在Delphi中反射称为RTTI(Run-Time Type Information) 翻译过来的名称是"运行期类型信息",也就是说可以在运行期获得数据类型或类(class)的信息

反射在我们普通程序开发中基本使用不到,但是在我们底层的程序设计中使用特别广泛,例如代理模式、工厂模式等一些设计模式,包括我们使用的开发工具以及各大开源框架底层都使用到了反射的原理。

# 运行期类型信息概述

运行期类型信息(RTTI)是一种语言特征,能使应用程序在运行时得到关于对象的信息

运行期类型信息(RTTI)是一种语言特征,能使应用程序在运行时得到关于对象的信息。RTTI是Delphi的组件能够融合到IDE中的关键。它在IDE中不仅仅是一个纯学术的过程。

由于对象都是从TObject继承下来的,因此,对象都包含一个指向它们的RTTI的指针以及几个内建的方法。下面的表列出了TObject的一些方法,用这些方法能获得某个对象实例的信息。

函数 返回类型 返回值
ClassName( ) string 对象的类名
ClassType() boolean 对象的类型
InheritsFrom boolean 判断对象是否继承于一个指定的类
ClassParent() TClass 对象的祖先类型
Instancesize() word 对象实例的长度(字节数)
ClassInfo() Pointer 指向RTTI的指针

# 初识反射

反射,从这个"反"字可以看出与我们平时正常的使用逻辑肯定不一样,那么到底什么地方不一样了?想要了解"反",就得先了解一下"正"的概念。

在正常情况下,如果要使用一个类,必须要经过以下几个步骤:

  • 使用uses导入类所在的单元

  • 通过构造方法(Create)进行类对象实例化

  • 产生对象可以使用"对象.属性"进行类中属性的调用

  • 通过"对象.函数()"调用类中的函数

在反射中,使用一个类并不需要导入类的所在单元,只要知道类的完整路径就可以知道该类中的所有信息

此外在Delphi中并不是所有的类都会存储到Rtti中的.只有那些在函数或类中被引用过的对象才会被自动添加到Rtti中,如果你想强制将所有的类都加入到Rtti中,那么只需要一个简单的预编译命令就可以了{$STRONGLINKTYPES ON}

uses rtti, System.StrUtils;
{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
  Ctx: TRttiContext;
  list: TArray<TRttiType>;
  typ: TRttiType;
  instance: TRttiInstanceType;
  QRClass: TClass;
  metodo: TRttiMethod;
begin
  Self.Memo1.Clear;
  Ctx := TRttiContext.Create;
  //该方法需要{$STRONGLINKTYPES ON}指令的支持
  //Ctx.FindType('Unit2.TPersion').Name;
  //获取运行期类型
  typ := Ctx.GetType(TPersion);
  // 获取运行期类型实例
  instance := typ.AsInstance;
  //通过运行期实例获取引用类型
  QRClass := instance.MetaclassType;
  //获取构造方法
  metodo := instance.GetMethod('Create');
  //通过构造方法获取对象
  Self.Memo1.Lines.Add(metodo.Invoke(QRClass, []).ToString);
  //调用方法
  typ.GetMethod('show').Invoke(metodo.Invoke(QRClass, []), []);

  Ctx.Free;
end;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

上面的代码仅仅是作为一个示例,演示了反射的方式调用对象中函数的过程,更多的功能需要我们自己去摸索学习

RTTI相关信息并不多,我在调用其他单元类创建对象的时候一直在报错,翻遍无数的网页才在一个老外提问的答案中查到需要添加预编译指令,反射这种技术初学的时候很可能会感觉没什么用,但是一旦当你需要编写一个具有通用性质的工具时就会发现它绝对是一把利器

上次更新: 2022/05/05, 14:24:28
异常处理
泛型容器

← 异常处理 泛型容器→

Theme by Vdoing | Copyright © 2013-2022 冀ICP备16006233号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×