4

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.

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

4 に答える 4

7

これはあなたが見つけた奇妙な振る舞いです。次を使用してタイプを見つけることができます。

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.
于 2010-06-08T16:08:30.117 に答える
7

問題は、インターフェイスを実装するクラスの VMT にも typeinfo にも、これらのインターフェイスの typeinfo への参照が含まれていないことです。インターフェイスの typeinfo は、プログラムで特に参照されていない場合、リンカによって削除されます。これを修正するには、クラスが実装されたインターフェイスの typeinfo を参照するように typeinfo 形式を変更する必要があります。そうしないと、すべてのインターフェイスを実行可能ファイルに強くリンクする必要があります。クラスの typeinfo に参照を実際に含めずに、リンクされたクラスによって実装される強力なリンク インターフェイスなど、他の種類の修正は、コンパイラの統合スマート リンカがどのように機能するかによって問題になります。

この問題を回避する別の方法は、ディレクティブを使用すること{$STRONGLINKTYPES ON}です。これにより、EXE、BPL、または DLL のルート型テーブル (RTL が修飾名を型にマップできるようにするインデックス) 内のすべての型が、弱いフィックスアップではなく強力なフィックスアップでリンクされます。それらを参照する弱いフィックスアップのみを持つシンボルは、スマート リンカによって削除されます。1 つ以上の強いフィックスアップがシンボルを参照する場合、それは最終的なバイナリに含まれ、弱い参照は nil されません (実際には @PointerToNil)。

他の回答で説明されているようにTypeInfo(ITheInterface)、非デッドコードで問題を修正します。これは、TypeInfo() マジック関数がインターフェイスに強力な修正を作成するためです。

于 2010-06-17T16:50:50.477 に答える
0

IMyPrettyLittleInterface には GUID がありますか? そうでない場合、RTTI システムはそれを認識しないと思います。

于 2010-06-08T13:42:01.877 に答える
0

RTTI は、$Mスイッチがアクティブな間に宣言された型に対して生成されます。すべてのコンパイラ ディレクティブと同様に、このスイッチにはユニット単位のスコープがあります。DPR ファイルで設定しますが、その設定は型を宣言したユニットでは効果がありません。

インターフェイスとクラスの宣言の前にそのスイッチを設定します。

type
  {$M+}
  IMyPrettyLittleInterface = interface
    ['{6F89487E-5BB7-42FC-A760-38DA2329E0C5}']
  end;
  TMyIntfClass = class(TInterfacedObject, IMyPrettyLittleInterface)
  end;
于 2010-06-08T14:45:25.380 に答える