这并没有什么特别的。
匿名方法被实现为一个编译器生成的接口,该接口具有与匿名方法相同签名的Invoke()
方法。 这就是为什么TTypeKind
是tkInterface
,IntfParent
是IInterface
。
在接口之后是包含捕获变量和匿名方法体的编译器生成的实现类,在其Invoke()
实现中。
匿名方法是怎样实现的?
IntfFlags
是一个TIntfFlagsBase
,它是一个包含Set
的TIntfFlag
枚举值的集合:
TIntfFlag = (ifHasGuid, ifDispInterface, ifDispatch)
ifHasGuid
接口具有全局唯一标识符(GUID)。
ifDispInterface
是一个分发接口。
ifDispatch
可以被分派。
Set
是一个值的位掩码。每个枚举值在掩码中都由特定位表示。在 TIntfFlagsBase
中,ifHasGuid
是第0位、ifDispInterface
是第1位,ifDispatch
是第2位。因此,数字值为6 (110b
) 表示启用了 ifDispInterface
和 ifDispatch
标志,但未启用 ifHasGuid
标志。因此,IntfGuid
没有实际意义,但对于对齐目的仍然占据了 TTypeData
中的空间。
更新:我使用 XE2 进行了测试,确实看到 IntfFlags
被设置为序数64 (TIntfFlag(6)
,与您看到的相同),而不是预期的序数6。我看到和您看到之间唯一的差异是,我看到 Guid
完全为空(全部为零)。
更新:显然,对于启用了方法信息({$M+}
指令)的接口,或者表示匿名方法类型的接口,存在其他标志未在 TIntfFlag
枚举中表示。我已经为此提交了一个错误报告:
RSP-24631: System.TypInfo.TIntfFlag enum is missing flags
在这种情况下,TIntfFlag(6)
是匿名方法的标志。
来源:未记录的 IInvokable 接口标志?:
It seems indeed as if the TIntfFlag enum was never extended since Delphi6 (I think that was when interface RTTI was introduced) - I can confirm that at least since XE an interface type with $M+ gets a fourth flag (lets call it ifHasMethodInfo) set.
If the type is an anonymous method type ... then there is a 7th enum value in the set. The situations where bit 5 and 6 are set are unknown to me.
...
I can confirm my findings with this code:
uses
SysUtils,
Rtti;
type
TIntfFlagEx = (ifHasGuid, ifDispInterface, ifDispatch, ifMethodInfo, ifUnknown, ifUnknown2, ifAnonymousMethod);
TIntfFlagsEx = set of TIntfFlagEx;
{$M+}
IFoo = interface
['{35CFB4E2-4A13-48E9-8026-C1558001F4B7}']
procedure Main;
end;
{$M-}
{$M+}
IBar = interface(TProc)
['{AB2FEC1A-339F-4E58-B3DB-EC7B734F461B}']
end;
{$M-}
{$M+}
TMyProc = reference to procedure;
{$M-}
procedure PrintIntf(typeInfo: Pointer);
var
context: TRttiContext;
rttiInterface: TRttiInterfaceType;
flags: TIntfFlagsEx;
begin
rttiInterface := context.GetType(typeInfo) as TRttiInterfaceType;
flags := TIntfFlagsEx(rttiInterface.IntfFlags);
Writeln(rttiInterface.Name, ' ', TValue.From(flags).ToString);
end;
begin
PrintIntf(TypeInfo(IInterface));
PrintIntf(TypeInfo(IInvokable));
PrintIntf(TypeInfo(IFoo));
PrintIntf(TypeInfo(TProc));
PrintIntf(TypeInfo(TFunc<Integer>));
PrintIntf(TypeInfo(TMyProc));
PrintIntf(TypeInfo(IBar));
Readln;
end.
prints this:
IInterface [ifHasGuid]
IInvokable [ifMethodInfo]
IFoo [ifHasGuid,ifMethodInfo]
TProc [ifAnonymousMethod]
TFunc [ifAnonymousMethod]
TMyProc [ifMethodInfo,ifAnonymousMethod]
IBar [ifHasGuid,ifMethodInfo,ifAnonymousMethod]
TIntfFlagsBase
的数值为64,则TIntfFlags
需要有7个元素,但事实并非如此。我认为您对问题的诊断有误。另外,您也不应该直接访问TI.TypeData
,而应该将TI
传递给GetTypeData()
。 - Remy Lebeau.TypeData
与传递给GetTypeData
相同,它是TTypeInfo
上的一个方法。此外,他没有误诊问题。在匿名方法类型的typeinfo中似乎存在一些垃圾数据(或一些未记录的标志)。 - Stefan GlienkeTIntfFlag
定义确实缺少几个标志。我已向 Embarcadero 报告了此问题。 - Remy Lebeau