匿名函数是用Interface来实现的,具体细节可以看
http://www.raysoftware.cn/?p=38
匿名函数还是非常方便的。
比如自己封装的异步调用。
Async(procedure(AParam : TValue)
      begin
      end,
       procedure (AParam : TValue; AResult: TValue)
       begin
       end );
第一个匿名函数,第一个是在线程内执行的,第二个是当异步执行完的回调,在主线程执行。用起来分厂方便。
不过Delphi的匿名函数我觉得不如C++的Lamda方便,也不如Java的接口回调方便。不过很多时候比之前做什么事情都要正儿八经封装一个class再写一个事件方便很多。

http://bbs.2ccc.com/topic.asp?topicid=529818

自从Delphi2009以后增加了一种匿名方法.

通过反汇编跟踪发现是编译器利用插入接口,类,对象来实现的.

Delphi2010刚好有RTTI的增强.我们就可以还原这个接口和类.至于RTTI的用法可以参看我前面的文章.

说干就干,挽袖子操刀

多余的话不多说.

procedure Test(Strs : TStrings);
type
TProc = reference to function () : TObject;
var
p : TProc;
R : TRttiContext;
RT : TRttiType;
Fs : TArray<TRttiField>;
MS : TArray<TRttiMethod>;
I : Integer;
Obj : TObject;
Interfaces : string;
begin
Strs.Clear;
p := function () : TObject
begin
//
asm
mov Result, eax //如果这个Anymouse方法被编译成成员方法的话,因为Delphi默认的Register调用约定,EAX中方的肯定是Self.
end;
//其实这句汇编代码不加应该也可以.因为固然Self在EAX中,Result也是EAX.所以写成空函数也没问题.这里这样写是为了更好读
end;

Obj := p();
R := TRttiContext.Create;
RT := R.GetType(Obj.ClassType);
FS := RT.GetFields();
MS := RT.GetMethods();

Strs.Add(‘======================================================’);
Strs.Add(Format(‘Obj[%0.8x],ClassName[%s],InstanceSize[%d],UnitName[%s]‘,[Integer(Obj), obj.ClassName, Obj.InstanceSize, obj.UnitName]));
Strs.Add(‘编译器会生成一个临时类,绑定一个临时接口的.类名规则是:Anymouse方法所在函数名+$ActRec,所以这里就是Test$ActRec’);
Strs.Add(‘临时接口至少有一个方法是Anymouse方法.但是通过RTTI我们未必能获取这个方法.因为尽管接口中的方法一定是Public的’);
Strs.Add(‘但是临时类的实现中该方法完全可能是Private或者Protected的.这样RTTI是取不到这些方法的’);
Strs.Add(‘======================================================’);
Strs.Add(‘类的形式如下:’);
for I := 0 to Obj.GetInterfaceTable()^.EntryCount – 1 do
if I = 0 then
Interfaces := Format(‘[%s]‘,[GUIDToString(Obj.GetInterfaceTable()^.Entries[i].IID)])
else
Interfaces := Interfaces + ‘,’+ Format(‘[%s]‘,[GUIDToString(Obj.GetInterfaceTable()^.Entries[i].IID)]);
Strs.Add(‘Type’);
Strs.Add(format(‘Class %s = class(%s,%s) //如果GUID全零,说明绑定的该接口没有GUID’,[obj.ClassName, obj.ClassParent.ClassName, Interfaces]));
for I := 0 to Length(FS) – 1 do
Strs.Add(Format(‘? %s : %s;//继承自%s’,[FS[i].Name, FS[i].FieldType.Name ,Fs[i].Parent.Name]));
for I := 0 to Length(MS) – 1 do
Strs.Add(Format(‘? %s;//继承自%s’,[MS[i].ToString(), MS[i].Parent.Name]));
Strs.Add(‘end;’);

R.Free;

end;

procedure TForm2.btn1Click(Sender: TObject);
begin
Test(memo1.Lines);
end;

那么点击Form上的按钮以后Memo1的内容就是:

======================================================
Obj[00AEA330],ClassName[Test$ActRec],InstanceSize[20],UnitName[Unit2]
编译器会生成一个临时类,绑定一个临时接口的.类名规则是:Anymouse方法所在函数名+$ActRec,所以这里就是Test$ActRec
临时接口至少有一个方法是Anymouse方法.但是通过RTTI我们未必能获取这个方法.因为尽管接口中的方法一定是Public的
但是临时类的实现中该方法完全可能是Private或者Protected的.这样RTTI是取不到这些方法的
======================================================
类的形式如下:
Type
Class Test$ActRec = class(TInterfacedObject,[{00000000-0000-0000-0000-000000000000}]) //如果GUID全零,说明绑定的该接口没有GUID
FRefCount : Integer;//继承自TInterfacedObject
procedure AfterConstruction;//继承自TInterfacedObject
procedure BeforeDestruction;//继承自TInterfacedObject
class function NewInstance: TObject;//继承自TInterfacedObject
constructor Create;//继承自TObject
procedure Free;//继承自TObject
class function InitInstance(Instance: Pointer): TObject;//继承自TObject
procedure CleanupInstance;//继承自TObject
function ClassType: TClass;//继承自TObject
class function ClassName: string;//继承自TObject
class function ClassNameIs(const Name: string): Boolean;//继承自TObject
class function ClassParent: TClass;//继承自TObject
class function ClassInfo: Pointer;//继承自TObject
class function InstanceSize: Integer;//继承自TObject
class function InheritsFrom(AClass: TClass): Boolean;//继承自TObject
class function MethodAddress(const Name: ShortString): Pointer;//继承自TObject
class function MethodAddress(const Name: string): Pointer;//继承自TObject
class function MethodName(Address: Pointer): string;//继承自TObject
function FieldAddress(const Name: ShortString): Pointer;//继承自TObject
function FieldAddress(const Name: string): Pointer;//继承自TObject
function GetInterface(const IID: TGUID; out Obj): Boolean;//继承自TObject
class function GetInterfaceEntry(const IID: TGUID): PInterfaceEntry;//继承自TObject
class function GetInterfaceTable: PInterfaceTable;//继承自TObject
class function UnitName: string;//继承自TObject
function Equals(Obj: TObject): Boolean;//继承自TObject
function GetHashCode: Integer;//继承自TObject
function ToString: string;//继承自TObject
function SafeCallException(ExceptObject: TObject; ExceptAddr: Pointer): HRESULT;//继承自TObject
procedure AfterConstruction;//继承自TObject
procedure BeforeDestruction;//继承自TObject
procedure Dispatch(var Message);//继承自TObject
procedure DefaultHandler(var Message);//继承自TObject
class function NewInstance: TObject;//继承自TObject
procedure FreeInstance;//继承自TObject
class destructor Destroy;//继承自TObject
end;

我们再看如果有多个Anymouse方法的话是怎样处理的.

procedure Test(Strs : TStrings);
type
TProc = reference to function () : TObject;
var
p : TProc;
R : TRttiContext;
RT : TRttiType;
Fs : TArray<TRttiField>;
MS : TArray<TRttiMethod>;
I : Integer;
Obj : TObject;
Interfaces : string;
begin
Strs.Clear;
p := function () : TObject
begin
//
asm
mov Result, eax //如果这个Anymouse方法被编译成成员方法的话,因为Delphi默认的Register调用约定,EAX中方的肯定是Self.
end;
//其实这句汇编代码不加应该也可以.因为固然Self在EAX中,Result也是EAX.所以写成空函数也没问题.这里这样写是为了更好读
end;

Obj := p();
R := TRttiContext.Create;
RT := R.GetType(Obj.ClassType);
FS := RT.GetFields();
MS := RT.GetMethods();

Strs.Add(‘======================================================’);
Strs.Add(Format(‘Obj[%0.8x],ClassName[%s],InstanceSize[%d],UnitName[%s]‘,[Integer(Obj), obj.ClassName, Obj.InstanceSize, obj.UnitName]));
Strs.Add(‘编译器会生成一个临时类,绑定一个临时接口的.类名规则是:Anymouse方法所在函数名+$ActRec,所以这里就是Test$ActRec’);
Strs.Add(‘临时接口至少有一个方法是Anymouse方法.但是通过RTTI我们未必能获取这个方法.因为尽管接口中的方法一定是Public的’);
Strs.Add(‘但是临时类的实现中该方法完全可能是Private或者Protected的.这样RTTI是取不到这些方法的’);
Strs.Add(‘======================================================’);
Strs.Add(‘类的形式如下:’);
for I := 0 to Obj.GetInterfaceTable()^.EntryCount – 1 do
if I = 0 then
Interfaces := Format(‘[%s]‘,[GUIDToString(Obj.GetInterfaceTable()^.Entries[i].IID)])
else
Interfaces := Interfaces + ‘,’+ Format(‘[%s]‘,[GUIDToString(Obj.GetInterfaceTable()^.Entries[i].IID)]);
Strs.Add(‘Type’);
Strs.Add(format(‘Class %s = class(%s,%s) //如果GUID全零,说明绑定的该接口没有GUID’,[obj.ClassName, obj.ClassParent.ClassName, Interfaces]));
for I := 0 to Length(FS) – 1 do
Strs.Add(Format(‘? %s : %s;//继承自%s’,[FS[i].Name, FS[i].FieldType.Name ,Fs[i].Parent.Name]));
for I := 0 to Length(MS) – 1 do
Strs.Add(Format(‘? %s;//继承自%s’,[MS[i].ToString(), MS[i].Parent.Name]));
Strs.Add(‘end;’);

R.Free;

//===========================================================================
p := function () : TObject
begin

asm
mov Result, eax
end;
GetTickcount(); //稍加变化
end;

Obj := p();
R := TRttiContext.Create;
RT := R.GetType(Obj.ClassType);
FS := RT.GetFields();
MS := RT.GetMethods();

Strs.Add(‘======================================================’);
Strs.Add(Format(‘Obj[%0.8x],ClassName[%s],InstanceSize[%d],UnitName[%s]‘,[Integer(Obj), obj.ClassName, Obj.InstanceSize, obj.UnitName]));
Strs.Add(‘编译器会生成一个临时类,绑定一个临时接口的.类名规则是:Anymouse方法所在函数名+$ActRec,所以这里就是Test$ActRec’);
Strs.Add(‘临时接口至少有一个方法是Anymouse方法.但是通过RTTI我们未必能获取这个方法.因为尽管接口中的方法一定是Public的’);
Strs.Add(‘但是临时类的实现中该方法完全可能是Private或者Protected的.这样RTTI是取不到这些方法的’);
Strs.Add(‘======================================================’);
Strs.Add(‘类的形式如下:’);
for I := 0 to Obj.GetInterfaceTable()^.EntryCount – 1 do
if I = 0 then
Interfaces := Format(‘[%s]‘,[GUIDToString(Obj.GetInterfaceTable()^.Entries[i].IID)])
else
Interfaces := Interfaces + ‘,’+ Format(‘[%s]‘,[GUIDToString(Obj.GetInterfaceTable()^.Entries[i].IID)]);
Strs.Add(‘Type’);
Strs.Add(format(‘Class %s = class(%s,%s) //如果GUID全零,说明绑定的该接口没有GUID’,[obj.ClassName, obj.ClassParent.ClassName, Interfaces]));
for I := 0 to Length(FS) – 1 do
Strs.Add(Format(‘? %s : %s;//继承自%s’,[FS[i].Name, FS[i].FieldType.Name ,Fs[i].Parent.Name]));
for I := 0 to Length(MS) – 1 do
Strs.Add(Format(‘? %s;//继承自%s’,[MS[i].ToString(), MS[i].Parent.Name]));
Strs.Add(‘end;’);

R.Free;
Strs.Add(‘以上重复两次,发现对象地址都是一样的.说明临时类和临时对象都只创建一份.’);
Strs.Add(‘但是临时类绑定了两个接口.说明每个Anymouse方法都绑定到一个独立的Interface上.’);

end;

把Anymouse方法和对象解析部分在复制一遍.

执行后memo1的内容就是:

======================================================
Obj[00AE2960],ClassName[Test$ActRec],InstanceSize[24],UnitName[Unit2]
编译器会生成一个临时类,绑定一个临时接口的.类名规则是:Anymouse方法所在函数名+$ActRec,所以这里就是Test$ActRec
临时接口至少有一个方法是Anymouse方法.但是通过RTTI我们未必能获取这个方法.因为尽管接口中的方法一定是Public的
但是临时类的实现中该方法完全可能是Private或者Protected的.这样RTTI是取不到这些方法的
======================================================
类的形式如下:
Type
Class Test$ActRec = class(TInterfacedObject,[{00000000-0000-0000-0000-000000000000}],[{00000000-0000-0000-0000-000000000000}]) //如果GUID全零,说明绑定的该接口没有GUID
FRefCount : Integer;//继承自TInterfacedObject
procedure AfterConstruction;//继承自TInterfacedObject
procedure BeforeDestruction;//继承自TInterfacedObject
class function NewInstance: TObject;//继承自TInterfacedObject
constructor Create;//继承自TObject
procedure Free;//继承自TObject
class function InitInstance(Instance: Pointer): TObject;//继承自TObject
procedure CleanupInstance;//继承自TObject
function ClassType: TClass;//继承自TObject
class function ClassName: string;//继承自TObject
class function ClassNameIs(const Name: string): Boolean;//继承自TObject
class function ClassParent: TClass;//继承自TObject
class function ClassInfo: Pointer;//继承自TObject
class function InstanceSize: Integer;//继承自TObject
class function InheritsFrom(AClass: TClass): Boolean;//继承自TObject
class function MethodAddress(const Name: ShortString): Pointer;//继承自TObject
class function MethodAddress(const Name: string): Pointer;//继承自TObject
class function MethodName(Address: Pointer): string;//继承自TObject
function FieldAddress(const Name: ShortString): Pointer;//继承自TObject
function FieldAddress(const Name: string): Pointer;//继承自TObject
function GetInterface(const IID: TGUID; out Obj): Boolean;//继承自TObject
class function GetInterfaceEntry(const IID: TGUID): PInterfaceEntry;//继承自TObject
class function GetInterfaceTable: PInterfaceTable;//继承自TObject
class function UnitName: string;//继承自TObject
function Equals(Obj: TObject): Boolean;//继承自TObject
function GetHashCode: Integer;//继承自TObject
function ToString: string;//继承自TObject
function SafeCallException(ExceptObject: TObject; ExceptAddr: Pointer): HRESULT;//继承自TObject
procedure AfterConstruction;//继承自TObject
procedure BeforeDestruction;//继承自TObject
procedure Dispatch(var Message);//继承自TObject
procedure DefaultHandler(var Message);//继承自TObject
class function NewInstance: TObject;//继承自TObject
procedure FreeInstance;//继承自TObject
class destructor Destroy;//继承自TObject
end;
======================================================
Obj[00AE2960],ClassName[Test$ActRec],InstanceSize[24],UnitName[Unit2]
编译器会生成一个临时类,绑定一个临时接口的.类名规则是:Anymouse方法所在函数名+$ActRec,所以这里就是Test$ActRec
临时接口至少有一个方法是Anymouse方法.但是通过RTTI我们未必能获取这个方法.因为尽管接口中的方法一定是Public的
但是临时类的实现中该方法完全可能是Private或者Protected的.这样RTTI是取不到这些方法的
======================================================
类的形式如下:
Type
Class Test$ActRec = class(TInterfacedObject,[{00000000-0000-0000-0000-000000000000}],[{00000000-0000-0000-0000-000000000000}]) //如果GUID全零,说明绑定的该接口没有GUID
FRefCount : Integer;//继承自TInterfacedObject
procedure AfterConstruction;//继承自TInterfacedObject
procedure BeforeDestruction;//继承自TInterfacedObject
class function NewInstance: TObject;//继承自TInterfacedObject
constructor Create;//继承自TObject
procedure Free;//继承自TObject
class function InitInstance(Instance: Pointer): TObject;//继承自TObject
procedure CleanupInstance;//继承自TObject
function ClassType: TClass;//继承自TObject
class function ClassName: string;//继承自TObject
class function ClassNameIs(const Name: string): Boolean;//继承自TObject
class function ClassParent: TClass;//继承自TObject
class function ClassInfo: Pointer;//继承自TObject
class function InstanceSize: Integer;//继承自TObject
class function InheritsFrom(AClass: TClass): Boolean;//继承自TObject
class function MethodAddress(const Name: ShortString): Pointer;//继承自TObject
class function MethodAddress(const Name: string): Pointer;//继承自TObject
class function MethodName(Address: Pointer): string;//继承自TObject
function FieldAddress(const Name: ShortString): Pointer;//继承自TObject
function FieldAddress(const Name: string): Pointer;//继承自TObject
function GetInterface(const IID: TGUID; out Obj): Boolean;//继承自TObject
class function GetInterfaceEntry(const IID: TGUID): PInterfaceEntry;//继承自TObject
class function GetInterfaceTable: PInterfaceTable;//继承自TObject
class function UnitName: string;//继承自TObject
function Equals(Obj: TObject): Boolean;//继承自TObject
function GetHashCode: Integer;//继承自TObject
function ToString: string;//继承自TObject
function SafeCallException(ExceptObject: TObject; ExceptAddr: Pointer): HRESULT;//继承自TObject
procedure AfterConstruction;//继承自TObject
procedure BeforeDestruction;//继承自TObject
procedure Dispatch(var Message);//继承自TObject
procedure DefaultHandler(var Message);//继承自TObject
class function NewInstance: TObject;//继承自TObject
procedure FreeInstance;//继承自TObject
class destructor Destroy;//继承自TObject
end;
以上重复两次,发现对象地址都是一样的.说明临时类和临时对象都只创建一份.
但是临时类绑定了两个接口.说明每个Anymouse方法都绑定到一个独立的Interface上.

Delphi的Anymouse方法探秘的更多相关文章

  1. delphi cxgrid 使用方法

    delphi cxgrid 使用方法1.绑定数据 方法 cxGrid1DBTableView1.DataController.DataSource:=DataSource12.去掉"Drag ...

  2. Delphi面向对象的方法

    方法是属于一个给定对象的过程和函数,方法反映的是对象的行为而不是数据,前一篇提到的对象的两个重要的方法:构造方法和析构方法. 为了使对象能执行各种功能,你能在对象中定制方法 创建一个方法用两个步骤,首 ...

  3. Delphi基本图像处理方法汇总

    这篇文章主要介绍了Delphi基本图像处理方法,实例汇总了Delphi操作图像实现浮雕.反色.模糊.翻转等常用效果的方法,非常具有实用价值,需要的朋友可以参考下   本文实例汇总了Delphi基本图像 ...

  4. 孤荷凌寒自学python第二十四天python类中隐藏的私有方法探秘

    孤荷凌寒自学python第二十四天python类中隐藏的私有方法探秘 (完整学习过程屏幕记录视频地址在文末,手写笔记在文末) 今天发现了python的类中隐藏着一些特殊的私有方法. 这些私有方法不管我 ...

  5. Delphi中匿名方法动态绑定事件

    应恢弘之约,写了一个对其发布的匿名函数动态绑定到事件的封装,代码如下: type TAnonEvent=class public class function Wrap<T1,T2>(On ...

  6. Delphi GDI+ 安装方法

    [转]Delphi GDI+ 安装方法转自:万一博客(http://www.cnblogs.com/del/)GDI+ 是 Windows 的一个函数库, 来自 Windows\System32\GD ...

  7. JNI 翻译 转 Delphi 的 经验 方法

    首发在 ①FireMonkey[移动开发] 16523232 欢迎使用 FMX 开发手机程序的高手来访. 注意:如果您看了本文,翻译了 JNI,请发布到本群共享一份.不同意本规定的,请立即删除本文.凡 ...

  8. delphi中locate方法

    TDataSet控件以及它的继承控件,例如TSimpleDataSet/TClientDataSet等都可以使用Locate方法在结果数据集中查寻数据.程序首先必须使用SQL命令从后端数据库中取得数据 ...

  9. fastscript调用delphi方法和DELPHI调用FASTSCRIPT方法

    fastscript调用Delphi过程:  1. 先创建事件处理方法:TfsCallMethodEvent 2. 然后再用调用TfsScript.AddMethod方法,第一个参数为Delphi方法 ...

随机推荐

  1. 利用spingmvc及servlet实现对url的地址去除后缀,更改后缀为html

    效果图 1.在web.xml中加上如下配置.其实就是利用servlet的目录过滤,这样所有带有news的地址都会被拦截 <!-- restfull风格约定,去除前台超链接访问的后缀 --> ...

  2. 学习鸟哥的Linux私房菜笔记(1)——Linux系统入门

    今天在阿里云申请了一个centos系统的云服务器,以前对linux了解的只是皮毛,记了几个命令还给忘了,整了半天都弄不好,作为一个做过javaweb开发的coder实在是惭愧啊,决定从今天开始学习Li ...

  3. Vue Router的官方示例改造

    基于Vue Router 2018年8月的官方文档示例,改造一下,通过一个最简单的例子,解决很多初学者的一个困惑. 首先是官方文档示例代码 <!DOCTYPE html> <html ...

  4. PHP设计模式——迭代模式

    声明:这一系列的博客引用<大话设计模式>.程洁作者. 迭代器模式:迭代器模式是遍历集合的成熟模式.迭代器模式的关键是将遍历集合的任务交给一个叫做迭代器的对象,它的工作时遍历并选择序列中的对 ...

  5. 从Client应用场景介绍IdentityServer4(二)

    原文:从Client应用场景介绍IdentityServer4(二) 本节介绍Client的ClientCredentials客户端模式,先看下画的草图: 一.在Server上添加动态新增Client ...

  6. python 简单的Socket编程

    python 编写server的步骤: 1第一步是创建socket对象.调用socket构造函数.如: socket = socket.socket(family, type ) family参数代表 ...

  7. DDD实战11 在项目中使用JWT的token 进行授权验证

    步骤: 1.首先要在webapi的管道中 使用认证(Authentication) 2.要在webapi的服务中注册验证条件 代码如下: namespace Dealer.WebApi { publi ...

  8. iOS8的APP过渡过程

    1. 2. watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveWluX3hpYW53ZWk=/font/5a6L5L2T/fontsize/400/fill/ ...

  9. Hopfield 神经网络及稳态性的证明

    根据其提出者,John Joseph Hopfield 命名.Hopfield 在 1982 年提出的划时代的:Neural networks and physical systems with em ...

  10. ThreadingTest(线程测试)领先的白框进入这个行业

    测试一直是黑色的,白点.在一般情况下,因为白盒测试需要逻辑思维能力是比较高的技术要求比一般开发商的项目经验和谨慎甚至更高,和较长的测试时间,用于单元测试,昂贵的工具,因此,国内企业普遍忽视白盒测试.这 ...