【问题标题】:Delphi RTTI unable to find interfaceDelphi RTTI 找不到接口
【发布时间】:2011-03-01 04:16:29
【问题描述】:

我正在尝试使用 D2010 RTTI 获取接口。

program rtti_sb_1;
{$APPTYPE CONSOLE}
{$M+}
uses
  SysUtils,
  Rtti,
  mynamespace in 'mynamespace.pas';
var
  ctx:      TRttiContext;
  RType:    TRttiType;
  MyClass:  TMyIntfClass;
begin
  ctx := TRttiContext.Create;
  MyClass := TMyIntfClass.Create;
  // This prints a list of all known types, including some interfaces.
  // Unfortunately, IMyPrettyLittleInterface doesn't seem to be one of them.
  for RType in ctx.GetTypes do
    WriteLn(RType.Name);
  // Finding the class implementing the interface is easy.
  RType := ctx.FindType('mynamespace.TMyIntfClass');
  // Finding the interface itself is not.
  RType := ctx.FindType('mynamespace.IMyPrettyLittleInterface');
  MyClass.Free;
  ReadLn;
end.

IMyPrettyLittleInterfaceTMyIntfClass = class(TInterfacedObject, IMyPrettyLittleInterface) 都在 mynamespace.pas 中声明,尤其是

unit mynamespace;
interface
type
  IMyPrettyLittleInterface = interface
    ['{6F89487E-5BB7-42FC-A760-38DA2329E0C5}']
  end;
  TMyIntfClass = class(TInterfacedObject, IMyPrettyLittleInterface)
  end;
  //...

有谁知道为什么这不起作用?有没有办法解决我的问题?提前致谢!

【问题讨论】:

    标签: delphi interface rtti


    【解决方案1】:

    问题在于 VMT 和实现接口的类的 typeinfo 都不包含对这些接口的 typeinfo 的任何引用。如果程序中没有另外引用,则连接器会消除接口的类型信息。要解决此问题,需要更改类型信息格式以使类引用已实现接口的类型信息,否则所有接口都需要强链接到可执行文件中。由于编译器的集成智能链接器的工作方式,其他类型的修复,例如由链接入类实现的强链接接口,但实际上在类 typeinfo 中没有包含引用,因此存在问题。

    解决此问题的另一种方法是使用指令{$STRONGLINKTYPES ON}。这将导致 EXE、BPL 或 DLL 的根类型表(让 RTL 将限定名称映射到类型的索引)中的所有类型都链接到强修正而不是弱修正。只有弱修正引用它们的符号被智能链接器消除;如果一个或多个强修复引用了该符号,那么它会包含在最终的二进制文件中,并且弱引用不会被 nil'ed(实际上是 @PointerToNil)。

    如其他答案中所述,非死代码中的TypeInfo(ITheInterface) 解决了该问题;这是因为 TypeInfo() 魔术函数创建了一个强大的接口修复。

    【讨论】:

      【解决方案2】:

      这是您发现的一种奇怪行为。您可以使用以下方法找到类型:

      RType := ctx.GetType(TypeInfo(IMyPrettyLittleInterface));
      

      但是一旦你这样做了,你就可以通过名字来访问它,所以如果你需要通过名字来访问它,你可以执行以下操作来使其工作。

      示例程序:

      program Project1;
      
      {$APPTYPE CONSOLE}
      
      uses
        SysUtils,
        Rtti,
        TypInfo,
        Unit1 in 'Unit1.pas';
      
      var
       ctx : TRttiContext;
       IType : TRttiType;
      begin;
        ctx := TRttiContext.Create;
        IType := ctx.FindType('Unit1.IExample');
        if Assigned(IType) then
        begin
          writeln('Found');
          Writeln(IType.QualifiedName);
        end
        else
          writeln('Not Found');
        ReadLn;
      end.
      

      示例单元:

      unit Unit1;
      
      interface
      
      type
        IExample = interface
          ['{D61F3245-13FB-44BF-A89D-BB358FAE7D19}']
        end;
      
      implementation
      uses Rtti;
      var
       C : TRttiContext;
      
      initialization
       C.GetType(TypeInfo(IExample));
      
      end.
      

      【讨论】:

      • 嗨罗伯特!感谢您的回答 - 效果很好!不过,这似乎很奇怪。目前,我将接受一种解决方法,但我当然希望它会在未来得到修复。你认为我应该向 QC 报告吗?
      • 是的,我认为它应该是 QC'ed。
      • 完成。现在报告为 QC #85277。
      • {$STRONGLINKTYPES ON} 也可以,其他详细信息请参阅我的答案。
      【解决方案3】:

      $M 开关处于活动状态时为声明的类型生成RTTI。与所有编译器指令一样,该开关具有 per-unit 范围。您在 DPR 文件中设置它,但该设置在您声明类型的单元中无效。

      在您的接口和类声明之前设置该开关:

      type
        {$M+}
        IMyPrettyLittleInterface = interface
          ['{6F89487E-5BB7-42FC-A760-38DA2329E0C5}']
        end;
        TMyIntfClass = class(TInterfacedObject, IMyPrettyLittleInterface)
        end;
      

      【讨论】:

      • 谢谢 Rob(还有 Paul-Jan),我忘了包括 $M 开关。不幸的是,它仍然不起作用。有人可以重现我的问题吗?
      • $M+ 根本不适用于 Delphi 2010 RTTI。
      【解决方案4】:

      IMyPrettyLittleInterface 是否有 GUID?如果没有,我认为 RTTI 系统不会识别它。

      【讨论】:

      • 嗨梅森!是的,它确实。我更新了我的帖子以反映实际的实施。我突然想到:我的 D2010 前几天更新了,我必须自己添加 {$M+},我相信这是过去为我完成的。也许 RTTI 在上次更新中被破坏了?
      • 您是否也尝试将 $M+ 添加到 mynamespace 单元?我假设你这样做了,但你的代码没有显示它。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-22
      • 2011-04-27
      • 1970-01-01
      • 2013-06-19
      • 2010-09-15
      相关资源
      最近更新 更多