比如我想写的代码是
procedure TForm11.FormCreate(Sender: TObject); begin Button1.OnClick := procedure(Sender: TObject) begin ShowMessage('Button1 Clicked'); end; end;这样直接编译不过去,因为一个是函数引用,是个是对象方法
函数引用 reference to procedure(Sender: TObject)
对象方法 procedure(Sender: TObject) of object;
带着疑问拜google,得到下面的解决方法,连接地址
procedure TForm11.FormCreate(Sender: TObject); begin @Button1.OnClick := PPointer(Cardinal(PPointer( procedure(Sender: TObject) begin ShowMessage('Button1 Clicked'); end )^) + $0C)^; end;很神奇,原理是说 匿名函数被编译器编译成了一个接口类,$0C的地址所指,也就是
我写代码测试了几次,能得出一个结论,在一个函数内定义的函数引用类型变量,会编译成“函数名$ActRec”的类(姑且叫ActRec),并只产生一个ActRec的实例,每个函数引用变量就对应着一个接口,有几个函数变量,就会有几个接口,然后这个ActRec都会实现这几个接口。
但是如果匿名函数太长,单独定义写呢
procedure TForm11.FormCreate(Sender: TObject); type TNotifyProc = reference to procedure(Sender: TObject); TNotifyXXX = reference to procedure(a: Integer; b: Integer); var B1,B2: TNotifyPro; Bi: Interface; Bo: TObject; xxx: TNotifyXXX; begin B1 := procedure(Sender: TObject) begin ShowMessage('Button1 Clicked'); end; B2 := procedure(Sender: TObject) begin ShowMessage('Button1 Clicked'); end; xxx := procedure(a: Integer; b: Integer) begin ShowMessage('xxx'); end; Bi := PUnknown(@B1)^; //函数引用其实是个接口来的 Bo := Bi as TObject; //将接口转为为实体类 showmessage(Bo.ClassName); //TForm11.FormCreate$ActRec,该类实现了3个接口 @Button1.OnClick := PPointer(Cardinal(PPointer( Integer(Bi) //可行 )^) + $0C)^; @Button1.OnClick := PPointer(Cardinal(PPointer( PInteger(@B1)^ //可行 )^) + $0C)^; @Button1.OnClick := PPointer(Cardinal(PPointer( Bo.GetInterfaceTable^.Entries[0].VTable //这样不行,为啥???? )^) + $0C)^;end;难道接口变量已经不是指向VTable所指了????
不过这种靠编译器的,毕竟不是好方法,继续找找看。
没有评论:
发表评论