2010-10-01 17 views
6

Necesito obtener el nombre de la unidad (espacio de nombres) de cualquier TRttiType.Obtener el nombre de la unidad que pertenece a cualquier tipo (TRttiType)

Hasta ahora, he intentado lo siguiente.

1) usando el PTypeData.UnitName, esta solución funciona, pero solo cuando el TTypeKind es 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) Analizar la propiedad QualifiedName, esta solución funciona bien hasta ahora, pero no estoy muy contento con él.

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 pregunta es, existe otra forma confiable de obtener el nombre de la unidad de cualquier TRttiType?

Respuesta

5

No parece que exista. El RTTI sale de la estructura TTypeData, que solo tiene un campo UnitName explícitamente declarado para tipos específicos. (Esto es anterior a D2010 y RTTI extendido.) Su número 2 parece ser la mejor manera de obtenerlo, y es probablemente cómo lo calcularía un TRTTIObject.UnitName hipotético si pusieran uno.

5

La información está allí, pero Analizar el nombre calificado es actualmente la mejor manera de llegar a él.

Si desea hacerlo de la manera difícil que pueda por:

En la unidad system.pas tiene una variable que contiene LibModuleList: PLibModule = nil; la lista de los módulos cargados. Este es el puntero a la información Raw RTTI que se puede usar sin RTTI.pas. Podría iterar toda la información sin procesar para determinar el nombre de la unidad.

Los valores clave de la TLibModule son:

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

Utilizando el TypeInfo: PPackageTypeInfo;, tendrá acceso a

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

Luego está TypeTable que contiene la información para llegar a PTypeInfo.
secuencia.

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

Un ejemplo de cómo funciona todo esto se puede encontrar en Rtti.pas TPackage.MakeTypeLookupTable es el método clave. Este método también muestra que QualifiedName siempre contendrá UnitName. Como tal, puede confiarse en su método original de análisis de QualfiedName.

Cuestiones relacionadas