2010-06-08 4 views
4

J'essaie d'aller chercher une interface en utilisant D2010 RTTI.Delphi RTTI impossible de trouver l'interface

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. 

Les deux IMyPrettyLittleInterface et TMyIntfClass = class(TInterfacedObject, IMyPrettyLittleInterface) sont déclarés dans mynamespace.pas, en particulier

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

Ne quelqu'un sait pourquoi cela ne fonctionne pas? Y a-t-il un moyen de résoudre mon problème? Merci d'avance!

Répondre

7

Ceci est un comportement étrange que vous avez trouvé. Vous pouvez trouver le type en utilisant:

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

Mais après avoir fait une fois, vous pouvez y accéder par son nom, donc si vous avez besoin d'y accéder par nom, vous pouvez faire ce qui suit pour le faire fonctionner.

Exemple de programme:

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. 

Exemple Unité:

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

Salut Robert! Merci pour votre réponse - cela fonctionne très bien! Cela semble étrange, cependant. Pour l'instant, je vais vivre avec une solution de contournement, mais j'espère que cela sera résolu dans le futur. Vous pensez que je devrais signaler au QC? – conciliator

+0

Oui je pense qu'il devrait être QC'ed. –

+0

Terminé. Il est maintenant signalé comme QC# 85277. – conciliator

0

Est-ce que IMyPrettyLittleInterface a un GUID? Je ne pense pas que le système RTTI le reconnaîtra si ce n'est pas le cas.

+0

Salut Mason! Oui. J'ai mis à jour mon message pour refléter la mise en œuvre réelle. Une idée m'a frappé: mon D2010 a été mis à jour l'autre jour, et j'ai dû ajouter le {$ M +} moi-même, ce que je crois avoir été fait pour moi dans le passé. Peut-être que RTTI a été cassé dans la dernière mise à jour? – conciliator

+0

Avez-vous essayé d'ajouter $ M + à l'unité mynamespace?Je suppose que vous l'avez fait, mais votre code ne le montre pas. –

+0

Un GUID n'est pas requis pour que le RTTI Delphi 2010 fonctionne. –

0

RTTI est généré pour les types déclarés alors que le commutateur $M est actif. Comme toutes les directives du compilateur, ce commutateur a une portée par unité. Vous l'avez défini dans votre fichier DPR, mais ce paramètre n'a aucun effet dans l'unité où vous avez déclaré vos types.

Set que l'interrupteur avant l'interface et les déclarations de classe:

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

Merci Rob (et Paul-Jan aussi), j'avais oublié d'inclure le commutateur $ M. Malheureusement, cela ne fonctionne toujours pas. Quelqu'un peut-il reproduire mon problème? – conciliator

+0

$ M + ne s'applique pas à Delphi 2010 RTTI du tout. –

7

Le problème est que ni le VMT, ni la typeinfo des classes qui implémentent une interface contiennent des références à la typeinfo de ces interfaces. Le typeinfo pour les interfaces est ensuite éliminé par l'éditeur de liens s'il n'est pas référencé dans le programme. Pour résoudre ce problème, il faudrait un changement de format typeinfo pour que les classes puissent référencer le typeinfo des interfaces implémentées, sinon toutes les interfaces devraient être fortement liées dans l'exécutable. D'autres types de correctifs, tels que les interfaces de liaison forte implémentées par des classes liées sans inclure de références dans le type de classe info, sont problématiques en raison de la manière dont fonctionne le lien intelligent intégré du compilateur.

Une autre solution à ce problème consiste à utiliser la directive {$STRONGLINKTYPES ON}. Cela provoquera tous les types dans la table de type racine EXE, BPL ou DLL (l'index qui permet à la liste RTL mapper les noms qualifiés de types) d'être liés avec des correctifs forts plutôt que des correctifs faibles. Les symboles qui n'ont que des correctifs faibles les référençant sont éliminés par l'éditeur de liens intelligent; Si une ou plusieurs fixups fortes référence le symbole, alors il est inclus dans le binaire final et les références faibles ne sont pas nulles (en fait @PointerToNil).

Comme décrit dans les autres réponses, TypeInfo(ITheInterface) dans le code non-mort résout le problème; C'est parce que la fonction magique TypeInfo() crée une forte correction à l'interface.

Questions connexes