Delphi中类方法作为参数/回调传递时Self为何自动绑定对应实例?
核心原理基础
Delphi的类实例方法指针并非单纯存储代码入口地址,而是一个携带实例上下文的闭包结构:
- 32位环境下占8字节,64位环境下占16字节
- 前半段存储方法的代码入口地址,后半段存储绑定的
Self实例地址
所有类实例方法都隐含Self作为第一个输入参数,编译器在执行实例方法时会自动把绑定的实例地址传入这个隐含参数。
问题1:TThread.Queue 调用实例方法时Self正确绑定的原因
TThread.Queue支持接收TThreadMethod类型参数,该类型的定义就是procedure of object,也就是标准的实例方法指针类型。
当你在TMyForm的实例方法内部书写oneProc(属于TMyForm的实例方法)时,编译器会自动把当前执行上下文的Self(也就是当前TMyForm实例地址)和oneProc的代码地址打包成完整的实例方法指针,传给TThread.Queue。TThread.Queue内部会完整存储这个闭包结构,等到主线程调度执行这个方法时,会自动把闭包里绑定的Self作为隐含参数传给oneProc,因此oneProc执行时Self必然是对应的TMyForm实例。
问题2:示例代码运行原理
示例代码如下:
procedure TMyForm.Button1Click(Sender: TObject); begin ProcA(ProcB); end; procedure TMyForm.ProcA(const Aproc: Tproc); begin Aproc; end; procedure TMyForm.ProcB; begin showmessage(self.className); // << 此处输出TMyForm,原理是什么? end;
运行逻辑完全符合上面的闭包原理:
- 触发
Button1Click时,这个方法的隐含Self参数就是当前的TMyForm实例 - 调用
ProcA(ProcB)时,ProcB作为TMyForm的实例方法,会被编译器自动打包为绑定了当前Self的方法指针,传给Aproc参数 - 执行
Aproc时,编译器自动把方法指针里绑定的TMyForm实例地址作为隐含参数传给ProcB - 因此
ProcB内部访问Self时,拿到的就是绑定的TMyForm实例,调用Self.ClassName自然输出TMyForm
内容的提问来源于stack exchange,提问作者zeus
相关产品推荐
相关产品推荐

