有没有一种方法可以从通用约束类型中获取GUID? [英] Is there a way to get GUID from a generic constraint type?

查看:80
本文介绍了有没有一种方法可以从通用约束类型中获取GUID?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在下面的示例代码中, 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆