匿名方法对TypeInfo的奇怪行为

Too*_*the 6 delphi anonymous-methods typeinfo delphi-10.2-tokyo

对于需要泛型类型"family"的一段代码,我尝试使用它TypeInfo来检索所需的信息.

class function GetTypeKind<T>:TTypeKind;
Run Code Online (Sandbox Code Playgroud)

对于大多数类型,我可以解决这个问题.但匿名方法类型表现出意外.

我有一个匿名方法类型定义为:

TMethodProc = reference to procedure;
Run Code Online (Sandbox Code Playgroud)

我试着获取类型信息:

MyKind := GetTypeKind<TMethodProc>;

class function GetTypeKind<T>:TTypeKind;
var 
  TI: PTypeInfo;
begin
  TI := TypeInfo(T);

  ...
end;
Run Code Online (Sandbox Code Playgroud)

我知道匿名方法背后有一些编译魔术.但我得到以下结果:

TI.TypeData.IntfParent == IInterface
TI.TypeData.IntfFlags == [(out of bounds)6]
Run Code Online (Sandbox Code Playgroud)

标志有一个意外的值,TIntfFlag有三个值,所以6是意外的.GUID也不是指导.它有一个相同的8个字节的重复集,大多数是00.例如(0,225,48,180,0,0,0,0,0,225,48,180,0,0,0,0)

匿名方法是否被排除在TypeInfo某些调整之外或者是否有用.

另外,(奇怪的)6是一个无证的特征,还是可以是任何值?

Rem*_*eau 5

这没有什么异常的。

匿名方法实现为由编译器生成的接口,该接口具有Invoke()与匿名方法匹配相同签名的方法。这就是为什么TTypeKindis tkInterface和the IntfParentis的原因IInterface

接口的后面是编译器生成的实现类,其中包含捕获的变量以及实现中的匿名方法的主体Invoke()

如何在后台实现匿名方法?

IntfFlagsTIntfFlagsBase,这是一个SetTIntfFlag枚举值:

TIntfFlag = (ifHasGuid, ifDispInterface, ifDispatch);
Run Code Online (Sandbox Code Playgroud)

ifHasGuid
接口具有一个GUID(全局唯一标识符)。

ifDispInterface
是一个调度接口。

ifDispatch
可以调度。

A Set是值的位掩码。每个枚举值由掩码中的特定位表示。在内TIntfFlagsBase,第ifHasGuid0 ifDispInterface位,第1位和第ifDispatch2位。因此,启用110bifDispInterfaceand ifDispatch标志是数值6(),而不是ifHasGuid标志。因此,IntfGuid并没有有意义的值,但仍然TTypeData为了对齐目的而占用的空间。


更新:我使用XE2进行了测试,可以肯定的是,我看到的IntfFlagsTIntfFlag(6)按预期设置为序数64(如您所见),而不是序数6。我所看到的与您所看到的之间的唯一区别是,我看到的Guid完全为空(全零)。


更新:显然,对于启用了方法信息({$M+}指令)或代表匿名方法类型的接口,确实存在其他标志,这些标志在TIntfFlag枚举中未表示。我已经为此提交了一个错误报告:

RSP-24631:System.TypInfo.TIntfFlag枚举缺少标志

在这种情况下,TIntfFlag(6)是匿名方法的标志。

IInvokable的未记录的“接口标志”?

自从Delphi6以来,似乎似乎从未对TIntfFlag枚举进行过扩展(我认为那是在引入接口RTTI时)-我可以确认,至少由于XE带有$ M +的接口类型获得了第四个标志(将其称为ifHasMethodInfo)设置了。

如果类型是匿名方法类型...,则该集合中有第7个枚举值。我不知道置位5和6的情况。

...

我可以使用以下代码确认我的发现:

TIntfFlag = (ifHasGuid, ifDispInterface, ifDispatch);
Run Code Online (Sandbox Code Playgroud)

打印此:

IInterface [ifHasGuid]
IInvokable [ifMethodInfo]
IFoo [ifHasGuid,ifMethodInfo]
TProc [ifAnonymousMethod]
TFunc [ifAnonymousMethod]
TMyProc [ifMethodInfo,ifAnonymousMethod]
IBar [ifHasGuid,ifMethodInfo,ifAnonymousMethod]

  • @RemyLebeau .TypeData与传递给GetTypeData相同,它是TTypeInfo上的方法。他也没有误诊这个问题。在typeinfo中似乎有一些用于匿名方法类型的垃圾数据(或一些未记录的标志)。 (2认同)