有没有一种方法可以从通用约束类型中获取GUID? [英] Is there a way to get GUID from a generic constraint type?
问题描述
在下面的示例代码中, Run< T>()
显示GUID IFoo
和 IFoo&T;
接口的值:
In the sample code below, the Run<T>()
displays the values of GUID IFoo
and IFoo<T>
interfaces:
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.
在这种情况下,是否可以从通用约束类型 IBar
接口获取 TGUID
或 PTypeInfo
?
Is there a way to get TGUID
or PTypeInfo
from a generic constraint type, IBar
interface in this case?
PS:我不想将 Run< T>()
的签名更改为 Run< T,U>()
,只是为了获得来自IBar的IBar
GUID.
P.S.: I wouldn't like change the signature of Run<T>()
to Run<T, U>()
for just get the IBar
GUID from U.
推荐答案
从泛型类型参数获取typeinfo/RTTI有点棘手,但并非完全不可能.
Getting typeinfo/RTTI from generic type parameters is a bit tricky but not completely impossible.
这是一些示例代码(我正在使用Spring.Reflections单元中的RTTI扩展).
Here is some example code how to do that (I am using the RTTI extensions from the Spring.Reflections unit).
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.
通过类型名称的字符串解析来检查类型是否为泛型.如果包含尖括号,则为通用类型.然后提取类型名称,这些类型名称始终是完全合格的类型名称,从而可以查找它们.
The check if the type is generic is done via string parsing of the type name. If it contains angle brackets it is a generic type. It then extracts the type names which are always full qualified type names which makes it possible to look them up.
但是要牢记一个陷阱.您只能在非通用类型参数的其他上下文中生成该类型的类型信息时才查找这些类型.这就是为什么在该示例中,我制作了一个简单的TBar类,该类实现了IBar并创建了一些实例以防止链接程序剥离该类(以及必要的RTTI).在实际代码中,这不是问题,因为您通常具有该接口的某些实现.同样,为了使该示例正常工作,您还需要将接口放在自己的单元中,因为按完整的合格名称查找不适用于dpr中的类型.
However there is one gotcha to keep in mind. You can only look those up when the type info for that type was generated in some other context than just the generic type parameter. That is why in that sample I made a simple TBar class that implements IBar and created some instance to prevent the linker to strip that class (and the necessary RTTI). In real code this is less of an issue because you typically have some implementations of that interface. Also for this example to work you need to put the interface into their own unit because lookup by full qualified name does not work for types in the dpr.
这篇关于有没有一种方法可以从通用约束类型中获取GUID?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!