在下面的示例代码中,Run<T>()
显示GUID IFoo
和IFoo<T>
接口的值:
type
IBar = interface
['{992E6597-42F1-40F8-B678-C4A86864B030}']
end;
IFoo = interface
['{0C589AF8-5727-4EAA-BB41-6D51D70B9D35}']
end;
IFoo<T> = interface(IFoo)
['{8FF54F6B-0896-4EA3-85F8-66BA70F9D2DA}']
end;
TTest = class
public
class procedure Run<T: IFoo>;
end;
class procedure TTest.Run<T>;
var
LContext: TRttiContext;
IFoo_T_TypeInfo: PTypeInfo;
IFooTypeInfo: PTypeInfo;
begin
IFoo_T_TypeInfo := TypeInfo(T);
IFooTypeInfo := LContext.GetType(TypeInfo(T)).BaseType.Handle;
WriteLn('IFoo<T> GUID: ', GetTypeData(IFoo_T_TypeInfo).GUID.ToString);
WriteLn('IFoo GUID: ', GetTypeData(IFooTypeInfo).GUID.ToString);
WriteLn('IBar GUID: ', '?');
end;
begin
TTest.Run<IFoo<IBar>>;
ReadLn;
end.
是否可以从通用约束类型TGUID
接口中获取PTypeInfo
或IBar
?
P.S .:我不想将Run<T>()
的签名更改为Run<T, U>()
,只是从美国获得IBar
GUID。
答案 0 :(得分:3)
从泛型类型参数获取typeinfo / RTTI有点棘手,但并非完全不可能。
这是一些示例代码(我正在使用Spring.Reflections单元中的RTTI扩展)。
uses
Rtti,
SysUtils,
Spring.Reflection;
type
TTest = class
public
class procedure Run<T: IFoo>;
end;
class procedure TTest.Run<T>;
var
LType, LType2: TRttiType;
begin
LType := TType.GetType(TypeInfo(T));
if LType.IsInterface then
begin
if LType.AsInterface.HasGuid then
Writeln(LType.Name, ' GUID: ', LType.AsInterface.GUID.ToString);
LType2 := LType.BaseType;
while Assigned(LType2) and (LType2.Handle <> TypeInfo(IInterface)) do
begin
if LType2.AsInterface.HasGuid then
Writeln(LType2.Name, ' GUID: ', LType2.AsInterface.GUID.ToString);
LType2 := LType2.BaseType;
end;
if LType.IsGenericType then
begin
for LType2 in LType.GetGenericArguments do
if Assigned(LType2) and LType2.IsInterface then
Writeln(LType2.Name, ' GUID: ', LType2.AsInterface.GUID.ToString);
end;
end
end;
var
bar: IBar;
begin
bar := TBar.Create; // cause RTTI for IBar to be generated to look it up later
TTest.Run<IFoo<IBar>>;
ReadLn;
end.
通过类型名称的字符串解析来检查类型是否为泛型。如果包含尖括号,则为通用类型。然后提取类型名称,这些类型名称始终是完全合格的类型名称,从而可以查找它们。
但是要记住一个陷阱。您只能在非通用类型参数的其他上下文中生成该类型的类型信息时才查找这些类型。这就是为什么在该示例中,我制作了一个简单的TBar类,该类实现了IBar并创建了一些实例以防止链接程序剥离该类(以及必需的RTTI)。在实际代码中,这不是问题,因为您通常具有该接口的某些实现。同样,为了使该示例正常工作,您还需要将接口放在自己的单元中,因为按完全限定名查找不适用于dpr中的类型。