Information for Structured Types
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 |
---|---|---|---|---|
Returns a specific field by its name. |
Yes |
Yes |
No | |
Returns a list of all (or only the declared) type's fields. |
Yes |
Yes |
No | |
Returns a specific method by its name. |
No |
Yes |
Yes | |
Returns a list of all (or only the declared) type's methods. |
No |
Yes |
Yes | |
Returns a specific property by its name. |
No |
Yes |
No | |
Returns a list of all (or only the declared) type's properties. |
No |
Yes |
No | |
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.