有没有办法从通用约束类型获取 GUID?

Is there a way to get GUID from a generic constraint type?

在下面的示例代码中,Run<T>() 显示 GUID IFooIFoo<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.

有没有办法从通用约束类型(在本例中为 IBar 接口)获取 TGUIDPTypeInfo

P.S.: 我不想将 Run<T>() 的签名更改为 Run<T, U>() 只是为了从 U.

获取 IBar GUID

从泛型类型参数中获取 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.

检查类型是否为泛型是通过类型名称的字符串解析完成的。如果它包含尖括号,则它是通用类型。然后它提取类型名称,这些名称始终是完全限定的类型名称,这使得查找它们成为可能。

然而,有一个问题需要牢记。只有当该类型的类型信息是在其他上下文中生成的,而不仅仅是泛型类型参数时,您才能查找这些信息。这就是为什么在该示例中我制作了一个实现 IBar 的简单 TBar class 并创建了一些实例以防止链接器剥离 class(和必要的 RTTI)。在实际代码中,这不是一个问题,因为您通常有该接口的一些实现。此外,为了使这个示例正常工作,您需要将接口放入它们自己的单元中,因为按完整限定名称查找不适用于 dpr 中的类型。