2010-06-08 117 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()魔術函數爲接口創建了一個強大的修復。