Information for Structured Types

From RAD Studio
Jump to: navigation, search

Go Up to Working with RTTI

Structured types in Delphi have far more information associated with them. This topic offers in-depth type information for structured types.

Static Arrays and Dynamic Arrays

Static arrays (or, simply, arrays) and dynamic arrays do not have the same RTTI object that describes them. TRttiArrayType is used for static arrays, while TRttiDynamicArrayType is used for dynamic arrays.

The properties exposed by TRttiArray are:

  • TotalElementCount, which specifies the total number of elements that this array can hold on all its dimensions.
  • ElementType, which gives type information for the array elements.
  • DimensionCount, which specifies the number of dimensions declared for the array.
  • Dimensions, which is an indexed property that returns the type information for the type that is used to denote the dimension (TRttiEnumerationType or TRttiOrdinalType).

The Dimensions property returns the type information of the type that provides the indexes in a dimension. For example, consider the following code:

type
    TMatrix = array [Boolean, 1 .. 10] of Integer;

var
    LContext: TRttiContext;
    LType: TRttiArrayType;
    LDimType: TRttiOrdinalType;
    LDimIndex: Integer;

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

    { Obtain the RTTI object }
    LType := LContext.GetType(TypeInfo(TMatrix)) as TRttiArrayType;

    { Enumerate all dimensions }
    for LDimIndex := 0 to LType.DimensionCount - 1 do
    begin
        LDimType := LType.Dimensions[LDimIndex] as TRttiOrdinalType;
        Writeln('Dimension ', LDimIndex, ' = [', LDimType.MinValue, '..',
          LDimType.MaxValue, ']');
    end;

end.
// C++ source code unavailable

The properties exposed by TRttiDynamicArray are:

  • ElementSize, which specifies the size of an element in the array.
  • ElementType, which gives the type information for the array elements.
  • OleAutoVarType, which specifies the OLE type for the array elements (if applicable).
  • DeclaringUnitName, which returns the name of the unit where the array was declared.

In the case of dynamic arrays, things are simpler, because dynamic arrays do not allow multiple dimensions and do not have a predefined size.

Classes, Interfaces, and Records

Structured types such as classes, records, and interfaces carry, along with the normal type information, additional information associated with their members. Depending on the actual type, some features are supported, while others are not:

Type/Member

Fields

Methods

Properties

Ancestry

Records

Yes

Yes

No

N/A

Classes

Yes

Yes

Yes

Yes

Interfaces

N/A

Yes

N/A

Yes


Class types are represented by TRttiInstanceType RTTI objects, record types are represented by TRttiRecordType objects, while interfaces are represented by TRttiInterfaceType objects.

You should note that, while only these three types support methods, fields, and interfaces, the actual methods and properties that allow access to this type information are located in TRttiType. This decision was made to ease the querying process. The following table lists the most important methods and properties that can be used with these structured types:

Methods

Description

Records

Classes

Interfaces

GetField

Returns a specific field by its name.

Yes

Yes

No

GetFields, GetDeclaredFields

Returns a list of all (or only the declared) type's fields.

Yes

Yes

No

GetMethod

Returns a specific method by its name.

No

Yes

Yes

GetMethods, GetDeclaredMethods

Returns a list of all (or only the declared) type's methods.

No

Yes

Yes

GetProperty

Returns a specific property by its name.

No

Yes

No

GetProperties, GetDeclaredProperties

Returns a list of all (or only the declared) type's properties.

No

Yes

No

BaseType

Returns the ancestor class or interface.

No

Yes

Yes


The following example demonstrates the difference between obtaining all members or only the declared ones:

var
    LContext: TRttiContext;
    LClass: TRttiInstanceType;
    LNewMethods, LNewFields, LNewProperties: Integer;

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

    { Obtain type information for TStringList }
    LClass := LContext.GetType(TStringList) as TRttiInstanceType;

    { Calculate the number of new methods, fields, and properties introduced in TStringList }
    LNewMethods := Length(LClass.GetMethods()) -
      Length(LClass.GetDeclaredMethods());
    LNewProperties := Length(LClass.GetProperties()) -
      Length(LClass.GetDeclaredProperties());
    LNewFields := Length(LClass.GetFields()) -
      Length(LClass.GetDeclaredFields());

    { Print the result onto the console }
    Writeln(Format
      ('%s introduces %d fields, %d methods, and %d properties relative to its %s ancestor',
      [LClass.Name, LNewFields, LNewMethods, LNewProperties,
      LClass.BaseType.Name]));

    LContext.Free;

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

    // Obtain type information for TStringList
    TRttiType *type = context->GetType(__delphirtti(TStringList));
    TRttiInstanceType *instanceType = dynamic_cast<TRttiInstanceType*>(type);
    if (!instanceType) {
        return 1; // failure to dynamic cast
    }

    // Calculate the number of new methods, fields, and properties introduced in TStringList
    const int newMethods = instanceType->GetMethods().Length -
        instanceType->GetDeclaredMethods().Length;
    const int newProperties = instanceType->GetProperties().Length -
        instanceType->GetDeclaredProperties().Length;
    const int newFields = instanceType->GetFields().Length -
        instanceType->GetDeclaredFields().Length;

    // Print the result onto the console
    printf("%ls introduces %d fields, %d methods, and %d properties relative to its %ls ancestor"
        , instanceType->Name.c_str(), newFields, newMethods, newProperties,
        instanceType->BaseType->Name.c_str());

    delete context;
    return 0;
}

Console output:

TStringList introduces 11 fields, 68 methods, and 14 properties relative to its
TStrings ancestor.

Note that overridden methods are also considered to be newly introduced.

See Also