Delphi RTTI не может найти интерфейс - PullRequest
4 голосов
/ 08 июня 2010

Я пытаюсь получить интерфейс, используя RTTI D2010.

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.

Оба IMyPrettyLittleInterface и TMyIntfClass = class(TInterfacedObject, IMyPrettyLittleInterface) объявлены в mynamespace.pas, в частности

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

Кто-нибудь знает, почему это не работает?Есть ли способ решить мою проблему?Заранее спасибо!

Ответы [ 4 ]

7 голосов
/ 17 июня 2010

Проблема в том, что ни VMT, ни typeinfo классов, которые реализуют интерфейс, не содержат никаких ссылок на typeinfo этих интерфейсов. Типинфо для интерфейсов затем удаляется компоновщиком, если в программе не указано иное. Чтобы исправить это, необходимо изменить формат typeinfo для классов, чтобы ссылаться на typeinfo реализованных интерфейсов, иначе все интерфейсы должны быть строго связаны с исполняемым файлом. Другие виды исправлений, такие как интерфейсы с сильными связями, которые реализуются связанными классами без фактического включения ссылок в класс typeinfo, проблематичны из-за того, как работает интегрированный интеллектуальный компоновщик компилятора.

Другим способом решения этой проблемы является использование директивы {$STRONGLINKTYPES ON}. Это приведет к тому, что все типы в таблице корневых типов EXE, BPL или DLL (индекс, позволяющий RTL сопоставлять квалифицированные имена с типами) будут связаны с сильными исправлениями, а не со слабыми исправлениями. Символы, которые имеют только слабые исправления, ссылающиеся на них, удаляются интеллектуальным компоновщиком; если одна или несколько сильных фиксаций ссылаются на символ, то он включается в конечный двоичный файл, а слабые ссылки не удаляются (на самом деле @PointerToNil).

Как описано в других ответах, TypeInfo(ITheInterface) в не мертвом коде устраняет проблему; это происходит потому, что магическая функция TypeInfo () создает сильное исправление интерфейса.

7 голосов
/ 08 июня 2010

Это странное поведение, которое вы обнаружили.Вы можете найти тип, используя:

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

Но после того, как вы сделали это один раз, вы можете получить к нему доступ по имени, поэтому, если вам нужно получить доступ к нему по имени, вы можете сделать следующее, чтобы он работал.1004 *

Пример программы:

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.
0 голосов
/ 08 июня 2010

RTTI генерируется для типов, объявленных при активном переключателе $M.Как и все директивы компилятора, этот переключатель имеет область действия на единицу .Вы устанавливаете его в своем файле DPR, но этот параметр не влияет на модуль, в котором вы объявили свои типы.

Установите этот переключатель до объявления интерфейса и класса:

type
  {$M+}
  IMyPrettyLittleInterface = interface
    ['{6F89487E-5BB7-42FC-A760-38DA2329E0C5}']
  end;
  TMyIntfClass = class(TInterfacedObject, IMyPrettyLittleInterface)
  end;
0 голосов
/ 08 июня 2010

Имеет ли IMyPrettyLittleInterface GUID? Я не думаю, что система RTTI распознает это, если не узнает.

...