2010-06-08 82 views
4

我想使用D2010 RTTI获取接口。德尔福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; 
    //... 

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

回答

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. 
+0

嗨,罗伯特!谢谢你的回答 - 它的效果非常好!这似乎很奇怪,但。目前,我会采取一种解决方法,但我确信希望它在未来能够得到解决。你认为我应该向QC报告? – conciliator 2010-06-08 16:43:39

+0

是的,我认为它应该被QC'ed。 – 2010-06-08 19:53:49

+0

完成。现在报告为QC#85277。 – conciliator 2010-06-09 06:26:58

0

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

+0

嗨梅森!是的,它确实。我更新了我的帖子以反映实际的实施情况。一个想法给我留下了深刻的印象:我的D2010有一天被更新了,我必须自己添加{$ M +},我相信这是我过去完成的。也许RTTI在上次更新中被打破了? – conciliator 2010-06-08 13:52:47

+0

您是否尝试向mynamespace单元添加$ M +以及?我假设你做了,但你的代码不显示它。 – 2010-06-08 14:36:08

+0

GUID不需要Delphi 2010 RTTI工作。 – 2010-06-08 16:09:31

0

RTTI是在$M开关处于活动状态时声明的类型生成的。像所有编译器指令一样,该开关具有每个单元范围内的。您将其设置在您的DPR文件中,但该设置在您声明类型的单元中没有效果。

设置您的接口和类声明之前切换:

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

感谢Rob(和Paul-Jan),我忘记了包含$ M开关。不幸的是,它仍然不起作用。有人可以重现我的问题吗? – conciliator 2010-06-08 15:29:11

+0

$ M +根本不适用于Delphi 2010 RTTI。 – 2010-06-08 15:49:46

7

的问题是,无论是VMT,也不是其实现接口的类的所属类别包含对这些接口的所属类别的任何引用。如果没有在程序中另行引用,那么接口的类型信息将被链接器清除。为了解决这个问题,需要对类进行typeinfo格式更改,以引用已实现的接口的typeinfo,否则所有接口都需要强连接到可执行文件中。由于编译器的集成智能链接程序的工作方式,其他类型的修补程序(如由链接类实现的强链接接口,实际上并未在类类型信息中包含引用)存在问题。

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

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