元类这里保存的FInstanceType实际上就是类似于Delphi中VMT指针的索引。 //-----------------------------------------Borland.Delphi.System.pas-- constructor _TClass.Create; begin inherited Create; end;
constructor _TClass.Create(ATypeHandle: System.RuntimeTypeHandle); begin inherited Create; FInstanceType := ATypeHandle; end;
constructor _TClass.Create(AType: System.Type); begin Create(AType.TypeHandle); end; //-----------------------------------------Borland.Delphi.System.pas-- 可以看到_TClass的几种形式构造函数,实际上都是围绕着这个Token做文章。 //-----------------------------------------Borland.Delphi.System.pas-- function _TClass.ClassParent: TClass; begin if not Assigned(FClassParent) then FClassParent := _TClass.Create(System.Type.GetTypeFromHandle(FInstanceType).BaseType.TypeHandle); Result := FClassParent; end; //-----------------------------------------Borland.Delphi.System.pas-- 而_TClass.FClassParent则是在需要时填充的父类的元类。注意这里的转换Token到 CLR中类型的方法。System.Type.GetTypeFromHandle函数和后面要使用到的 System.Type.GetTypeHandle函数完成Type与Token之间的双向转换。 因此可以说在Delphi.NET中,元类实际上就是对类的Token的一个封装。
在了解了元类的实现后,我们来看看如何从一个Token获取其元类。 //-----------------------------------------Borland.Delphi.System.pas-- var MetaTypeMap: Hashtable;
function _GetMetaFromHandle(ATypeHandle: System.RuntimeTypeHandle): _TClass; var t: System.Type; begin if not Assigned(MetaTypeMap) then MetaTypeMap := Hashtable.Create;
Result := _TClass(MetaTypeMap[ATypeHandle]); if not Assigned(Result) then begin t := System.Type.GetTypeFromHandle(ATypeHandle); t := t.GetNestedType(''''@Meta'''' + t.name, BindingFlags(Integer(BindingFlags.Public) or Integer(BindingFlags.NonPublic))); if Assigned(t) then begin Result := _TClass(t.GetField(''''@Instance'''').GetValue(nil)); MetaTypeMap.Add(ATypeHandle, Result); end else begin Result := _TClass.Create(ATypeHandle); end; end; end; //-----------------------------------------Borland.Delphi.System.pas-- Delphi.NET使用一个哈希表MetaTypeMap来缓存Token到元类的转换关系, 因为这种转换是耗时且较频繁的操作,这主要是为优化现有Delphi代码对元类的大量使用。 对一个Token,Delphi.NET先将其转换为一个Type类型,然后取其嵌套子类, 子类名就是@Meta前缀加类名,元类允许是公开或私有。 如果找到元类的类型,则从元类的@Instance字段获取值,也就是元类的一个实例; 否则使用此Token构造一个新的元类并返回。 这样Delphi.NET就完成了TClass机制在CLR环境下的映射。