2010-10-01 11 views
6

Potrzebuję uzyskać nazwę jednostki (przestrzeni nazw) dowolnego TRttiType.Uzyskiwanie nazwy jednostki, która należy do dowolnego typu (TRttiType)

do tej pory próbowałem następujące.

1) przy użyciu PTypeData.UnitName, to rozwiązanie działa, ale tylko wtedy, gdy TTypeKind jest 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) Przetwarzanie właściwość QualifiedName, to rozwiązanie działa ok do tej pory, ale nie jestem bardzo z niego zadowolony.

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; 

Pytanie brzmi, czy istnieje jeszcze jeden niezawodny sposób na uzyskanie nazwy jednostki dowolnego numeru TRttiType?

Odpowiedz

5

Wygląda na to, że nie ma. RTTI pochodzi ze struktury TTypeData, która ma tylko jedno pole UnitName jawnie zadeklarowane dla określonych typów. (To jest wcześniejsze niż D2010 i rozszerzona RTTI.) Twoje # 2 wygląda jak najlepszy sposób, aby go zdobyć, i prawdopodobnie jest to sposób, w jaki hipotetyczny TRTTIObject.UnitName obliczyłby go, gdyby go wprowadził.

5

Informacje są dostępne, ale Parsowanie kwalifikowanej nazwy jest obecnie najlepszym sposobem, aby się do niej dostać.

Jeśli chcesz zrobić to w przykry sposób można by:

W jednostce system.pas masz zmienną LibModuleList: PLibModule = nil; że zawiera listę załadowanych modułów. To jest wskaźnik do Raw RTTI Information, który może być użyty bez RTTI.pas. Możesz powtórzyć wszystkie surowe informacje i określić nazwę urządzenia.

Kluczowe wartości TLibModule są:

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

Używanie TypeInfo: PPackageTypeInfo; uzyskać dostęp do

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

Wtedy nie ma TypeTable który zawiera informacje, aby dostać się PTypeInfo.
sekwencji.

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

Przykładem tego, jak to wszystko działa można znaleźć w Rtti.pas TPackage.MakeTypeLookupTable jest metoda klucz. Ta metoda pokazuje również, że QualifiedName zawsze będzie zawierało nazwę UnitName. W związku z tym można polegać na oryginalnej metodach analizy QualfiedName.

Powiązane problemy