2010-10-01 9 views
6

Ho bisogno di ottenere il nome dell'unità (spazio dei nomi) di qualsiasi TRttiType.Ottenere l'unità Nome appartenente a qualsiasi tipo (TRttiType)

finora, ho provato quanto segue.

1) utilizzando il PTypeData.UnitName, questa soluzione funziona, ma solo quando TTypeKind è tkClass.

procedure ListAllUnits; 
var 
    ctx : TRttiContext; 
    lType: TRttiType; 
    Units: TStrings; 
begin 
    Units:=TStringList.Create; 
    try 
    ctx := TRttiContext.Create; 
    for lType in ctx.GetTypes do 
    if lType.IsInstance then //only works for classes 
     if Units.IndexOf(UTF8ToString(GetTypeData(lType.Handle).UnitName))<0 then 
     Units.Add(UTF8ToString(GetTypeData(lType.Handle).UnitName)); 
    Writeln(Units.Text); 
    finally 
    Units.Free; 
    end; 
end; 

2) Analisi della proprietà QualifiedName, questa soluzione funziona bene fino ad ora, ma non sono molto soddisfatto.

procedure ListAllUnits2; 

    function GetUnitName(lType: TRttiType): string; 
    begin 
    Result := StringReplace(lType.QualifiedName, '.' + lType.Name, '',[rfReplaceAll]) 
    end; 

var 
    ctx: TRttiContext; 
    lType: TRttiType; 
    Units: TStrings; 
begin 
    Units := TStringList.Create; 
    try 
    ctx := TRttiContext.Create; 
    for lType in ctx.GetTypes do 
     if Units.IndexOf(GetUnitName(lType)) < 0 then 
     Units.Add(GetUnitName(lType)); 
    Writeln(Units.Text); 
    finally 
    Units.Free; 
    end; 
end; 

la domanda è: esiste un modo affidabile per ottenere il nome dell'unità di qualsiasi TRttiType?

risposta

5

Non sembra che ci sia. RTTI esce dalla struttura TTypeData, che ha solo un campo UnitName dichiarato esplicitamente per tipi specifici. (Questo precede D2010 e RTTI esteso.) Il numero 2 sembra il modo migliore per ottenerlo ed è probabilmente il modo in cui un ipotetico TRTTIObject.UnitName lo calcolerebbe se ne inserisse uno.

5

Le informazioni sono presenti ma L'analisi del nome qualificato è attualmente il modo migliore per raggiungerla.

Se si vuole farlo nel modo più duro possibile da:

Nell'unità system.pas si dispone di una variabile che contiene LibModuleList: PLibModule = nil; la lista dei moduli caricati. Questo è il puntatore alle informazioni RTTI non elaborate che possono essere utilizzate senza RTTI.pas. È possibile scorrere tutte le informazioni non elaborate per determinare il nome dell'unità.

I valori chiave del TLibModule sono:

PLibModule = ^TLibModule; 
    TLibModule = record 
    Next: PLibModule; { Linked List of Loaded Modules) 
    Instance: LongWord; 
    ... 
    TypeInfo: PPackageTypeInfo; { List of contained Package Information } 
    ... 
    end; 

Utilizzando il TypeInfo: PPackageTypeInfo; è possibile accedere a

PPackageTypeInfo = ^TPackageTypeInfo; 
    TPackageTypeInfo = record 
    TypeCount: Integer; 
    TypeTable: PTypeTable; 
    UnitCount: Integer; 
    UnitNames: PShortString; { concatenation of Pascal strings, 
           one for each unit } 
    end; 

Poi c'è TypeTable che contiene le informazioni per arrivare a PTypeInfo.
sequenza.

TTypeTable = array[0..MaxInt div SizeOf(Pointer) - 1] of Pointer; 
    PTypeTable = ^TTypeTable; 

Un esempio di come funziona tutto questo può essere trovato in Rtti.pas TPackage.MakeTypeLookupTable è il metodo chiave. Questo metodo mostra anche che QualifiedName conterrà sempre il NomeUnità. In questo modo è possibile dipendere dal metodo originale di analisi di QualfiedName.