Querying for Type Information

From RAD Studio
Jump to: navigation, search

Go Up to Working with RTTI


Introduction

The starting point of any RTTI working session is obtaining the type information. In Delphi, type information is emitted only for types and not for global unit routines, constants, or variables. This means that the obtained TRttiContext can be used only to query for information about the declared types.

There are three basic methods to obtain information about a type:

  • Get a list of all the types declared in the application.
  • Find the information for a specific type, given its type information handle or qualified name.
  • Use the first two methods to query for types in individual run-time packages.

Enumerating All Types

To obtain a list of all the types declared in an application, use the TRttiContext.GetTypes method. It enumerates all publicly visible types (the ones declared in the interface section of units) and returns an array of TRttiType objects. Each TRttiType object provides a high-level API to access the information about the type it describes:

var
    LContext: TRttiContext;
    LType: TRttiType;
begin
    { Obtain the RTTI context }
    LContext := TRttiContext.Create;

    { Enumerate all types declared in the application }
    for LType in LContext.GetTypes() do
        Writeln(LType.Name);

    LContext.Free;
end.
int _tmain(int argc, _TCHAR* argv[]) {
    // Obtain the RTTI context
    TRttiContext *context = new TRttiContext();

    // Enumerate all types declared in the application
    DynamicArray<TRttiType*>typeArray = context->GetTypes();
    for (int i = 0; i < typeArray.Length; i++) {
        TRttiType *type = typeArray[i];
        printf("%ls\n", type->Name.c_str());
    }

    delete context;
    return 0;
}

The previous example obtains the RTTI context and then uses it to obtain the list of all publicly available types. The for loop then prints the names of the types to the console.

The TRttiType instances should not be cleaned up by the developer. As described in the previous topic, the TRttiContext is responsible for their lifetime management.

Getting Information for a Specific Type

If the name of the type for which information should be obtained at run time is known at compile time, TRttiContext includes other two methods:

  • TRttiContext.GetType, which obtains type information for a given System.TypInfo.PTypeInfo handle. The PTypeInfo handle is obtained at compile time, by using the TypeInfo operator.
  • TRttiContext.FindType, which looks up the type information based on the qualified type name. The qualified type name is made up of two components: unit name, separated by the dot character from the type name (for example, Classes.TStrings).

The following example demonstrates the use of the mentioned methods:

var
    LContext: TRttiContext;
    LType: TRttiType;

begin
    { Obtain the RTTI context }
    LContext := TRttiContext.Create;

    { Obtain the type information for Integer }
    LType := LContext.GetType(TypeInfo(Integer));
    Writeln(LType.Name);

    { Obtain the type information for a type in the Classes unit }
    LType := LContext.FindType('Classes.TStrings');
    if not LType.IsInstance then
        Writeln('Expected TStrings to be a class!');

    LContext.Free;
end.
int _tmain(int argc, _TCHAR* argv[]) {
    // Obtain the RTTI context
    TRttiContext *context = new TRttiContext();

    // Obtain the type information for Integer
    TRttiType *type = context->GetType(__delphirtti(Integer));
    printf("%ls\n", type->Name.c_str());

    type = context->FindType("Classes.TStrings");
    if ((type->IsInstance) == false) {
        puts("Expected TStrings to be a class!");
    }

    delete context;
    return 0;
}

Normally, GetType and FindType are useful at run time, when the name of the type or the PTypeInfo handle is obtained indirectly.

Package Information

TRttiContext exposes a special method, called TRttiContext.GetPackages, which allows you to enumerate over all run-time packages currently loaded into the application (including the main application module, which is also considered a package.) GetPackages returns an array of TRttiPackage instances. The instances expose a number of functions that allow obtaining the types specifically declared in the package:

var
    LContext: TRttiContext;
    LType: TRttiType;
    LPackage: TRttiPackage;

begin
    { Obtain the RTTI context }
    LContext := TRttiContext.Create;

    { Obtain the second package (rtl140) }
    LPackage := LContext.GetPackages()[1];

    { Enumerate all types in the rtl140 package }
    for LType in LPackage.GetTypes() do
        Writeln(LType.Name);

    LContext.Free;
end.
int _tmain(int argc, _TCHAR* argv[]) {
    // Obtain the RTTI context
    TRttiContext *context = new TRttiContext();

    // Obtain the second package (rtl140)
    DynamicArray<TRttiPackage*>packageArray = context->GetPackages();
    TRttiPackage *package = packageArray[1];

    // Enumerate all types in the rtl140 package
    DynamicArray<TRttiType*>typeArray = package->GetTypes();
    for (int i = 0; i < typeArray.Length; i++) {
        TRttiType *type = typeArray[i];
        printf("%ls\n", type->Name.c_str());
    }

    delete context;
    return 0;
}

The previous example obtains information about the secondly loaded package (in our case--rtl140.bpl) and then retrieves all the types exposed by that package. Note that the example must be built using run-time packages; otherwise, the types are built into the application directly.

The same as TRttiContext, TRttiPackage allows finding the type by its qualified name:

var
    LContext: TRttiContext;
    LType: TRttiType;
    LPackage: TRttiPackage;

begin
    { Obtain the RTTI context }
    LContext := TRttiContext.Create;

    { Obtain the second package (rtl140) }
    LPackage := LContext.GetPackages()[1];

    { Get type information for the TStrings class }
    LType := LPackage.FindType('Classes.TStrings');
    Writeln(LType.Name);

    LContext.Free;
end.
int _tmain(int argc, _TCHAR* argv[]) {
    // Obtain the RTTI context
    TRttiContext *context = new TRttiContext();

    // Obtain the second package (rtl140)
    DynamicArray<TRttiPackage*>packageArray = context->GetPackages();
    TRttiPackage *package = packageArray[1];

    // Get type information for the TStrings class
    TRttiType *type = package->FindType("Classes.TStrings");
    printf("%ls\n", type->Name.c_str());

    delete context;
    return 0;
}

See Also