Information for Simple Types

From RAD Studio
Jump to: navigation, search

Go Up to Working with RTTI

Introduction

In Delphi, there are two basic categories of types: simple and structured. In terms of type information, simple types usually carry far less information than structured types.

To verify whether the obtained TRttiType reflects a given type, use the TRttiType.TypeKind property. Its value specifies the actual type kind. The other method is to use the is operator to detect the actual class type for a TRttiType instance:

    { Display only the string types }
    for LType in LContext.GetTypes() do
        if LType is TRttiStringType then
            Writeln(LType.ToString);
    // Display only the string types
    DynamicArray<TRttiType*>typeArray = context->GetTypes();
    for (int i = 0; i < typeArray.Length; i++) {
        TRttiType *type = typeArray[i];
        TRttiStringType *stringType = dynamic_cast<TRttiStringType*>(type);
        if (stringType) {
            printf("%ls\n", stringType->ToString().c_str());
        }
    }

The previous example displays only the string types declared in the application and its packages.

Ordinal Types

Ordinal types are described by TRttiOrdinalType class instances. TRttiOrdinalType exposes properties used to access the information specific to ordinal types such as MinValue, MaxValue, and OrdType.

The following example enumerates all ordinal types defined in the application or its packages and prints their properties on the console:

    for LType in LContext.GetTypes() do
        if LType is TRttiOrdinalType then
        begin
            Writeln('Type name:', LType.Name);
            Writeln('Min allowed value:', TRttiOrdinalType(LType).MinValue);
            Writeln('Max allowed value:', TRttiOrdinalType(LType).MaxValue);
            Writeln;
        end;
    // Enumerate all types declared in the application
    DynamicArray<TRttiType*>typeArray = context->GetTypes();
    for (int i = 0; i < typeArray.Length; i++) {
        TRttiType *type = typeArray[i];
        TRttiOrdinalType *ordinalType = dynamic_cast<TRttiOrdinalType*>(type);
        if (ordinalType) {
            printf("%ls\n", ordinalType->ToString().c_str());
            printf("\t min value: %ld\n", ordinalType->MinValue);
            printf("\t max value: %ld\n", ordinalType->MaxValue);
        }
    }

Note that enumeration types are also considered ordinal, so the previous example will also print the information they contain.

64-bit Integer Types

64-bit integers do not share the same base type as the ordinal types. Because of this, 64-bit integers are described by the TRttiInt64Type class. TRttiInt64Type exposes the MinValue and MaxValue properties, similarly to TRttiOrdinalType.

The following example enumerates all 64-bit integers declared in the application or its packages:

    for LType in LContext.GetTypes() do
        if LType is TRttiInt64Type then
        begin
            Writeln('Type name:', LType.Name);
            Writeln('Min allowed value:', TRttiInt64Type(LType).MinValue);
            Writeln('Max allowed value:', TRttiInt64Type(LType).MaxValue);
            Writeln;
        end;
    DynamicArray<TRttiType*>typeArray = context->GetTypes();
    for (int i = 0; i < typeArray.Length; i++) {
        TRttiType *type = typeArray[i];
        TRttiInt64Type *int64Type = dynamic_cast<TRttiInt64Type*>(type);
        if (int64Type) {
            printf("type name: %ls\n", int64Type->ToString().c_str());
            printf("\t min allowed value: %Ld\n", int64Type->MinValue);
            printf("\t max allowed value: %Ld\n", int64Type->MaxValue);
        }
    }

Floating-Point Types

Floating-point types are described by TRttiFloatType class instances. TRttiFloatType exposes only one property, called FloatType, which allows identifying the floating-point subtype.

The following example prints all the declared floating-point types whose subtype is Double:

for LType in LContext.GetTypes() do
  if (LType is TRttiFloatType) and (TRttiFloatType(LType).FloatType = ftDouble) then
    Writeln('Type name:', LType.Name);

The printed results include the Double type itself, the Real type, which is a double type and date-time types declared in the System unit.

Set Types

Set types are described by TRttiSetType class instances. The only property exposed by TRttiSetType is ElementType, which provides type information for the elements that make up the set. For example, given a set defined as:

type
  TByteSet = set of Byte;

the following code prints the type name of the set of elements (which is Byte):

var
  LContext: TRttiContext;
  LType: TRttiSetType;

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

  { Obtain the TRttiSetType for our type }
  LType := LContext.GetType(TypeInfo(TByteSet)) as TRttiSetType;

  { Print the type name of the set elements }
  Writeln('The elements of the set are of ', LType.ElementType.Name, ' type.');
end.

Enumeration Types

Enumeration types are described by TRttiEnumerationType class instances. TRttiEnumerationType is derived from TRttiOrdinalType and adds up a new property, called UnderlyingType. UnderlyingType provides type information for the actual enumeration type that is used in this enumeration type.

Consider two enumeration types, one new and the other one being an alias of the standard TSeekOrigin enumeration:

type
  TNewEnum = (neOne, neTwo, neThree);
  TOtherEnum = type TSeekOrigin;

The following code prints the name of the underlying type for both types:

  { Obtain the type information for both types }
  LType1 := LContext.GetType(TypeInfo(TNewEnum)) as TRttiEnumerationType;
  LType2 := LContext.GetType(TypeInfo(TOtherEnum)) as TRttiEnumerationType;

  { Print the type names for the underlying types }
  Writeln('Underlying type for TNewEnum is ', LType1.UnderlyingType.Name);
  Writeln('Underlying type for TOtherEnum is ', LType2.UnderlyingType.Name);

You should note that, for newly declared enumeration types (for example, TNewEnum), the UnderlyingType property returns the type information for the enumeration type itself. For strong aliased types (such as TOtherEnum), UnderlyingType returns the type information of that type.

Strings

String types are described by TRttiStringType class instances. TRttiStringType exposes only one property, called StringKind, which allows identifying the actual string type. The string type can be:

  • Short string
  • Ansi string
  • Wide string
  • Unicode string

The following example prints all ANSI string types declared in the application or its packages:

for LType in LContext.GetTypes() do
  if (LType is TRttiStringType) and (TRttiStringType(LType).StringKind = skAnsiString) then
    Writeln(LType.Name);

For AnsiString types, the Rtti unit defines a special TRttiAnsiStringType class. TRttiAnsiStringType is derived from TRttiStringType and it adds a new CodePage property, which can be used to obtain the code page of the AnsiString.

The following example prints the code page of the RawByteString type:

{ Obtain type information for RawByteString (which is an AnsiString) }
LType := LContext.GetType(TypeInfo(RawByteString)) as TRttiAnsiStringType;
Writeln('The codepage of the string is ', LType.CodePage);

Class References (Metaclasses)

Class reference types are described by TRttiClassRefType class instances. TRttiClassRefType allows obtaining the class type that is used for the base of the hierarchy denoted by the metaclass (using the InstanceType property). TRttiClassRefType also provides direct access to the metaclass itself, through MetaclassType.

The following example prints all the metaclass types declared in the application or its packages; they represent types that are derived from TComponent:

var
  LContext: TRttiContext;
  LType: TRttiType;
  LMeta: TRttiClassRefType;

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

  { Get all types that are class references and whose class inherits from TComponent }
  for LType in LContext.GetTypes() do
    if (LType is TRttiClassRefType) then
    begin
      { Typecast the Rtti type class }
      LMeta := TRttiClassRefType(LType);

      if (LMeta.MetaclassType.InheritsFrom(TComponent)) then
      begin
        Writeln('The metaclass type name is ', LType.Name);
        Writeln('The hierarchy starts at ', LMeta.InstanceType.Name);
      end;
    end;
end.

To better understand the information listed by the previous example, consider this type definition:

type
  TButtonClass = class of TButton;

For this type, the MetaclassType property returns the metaclass itself, while the InstanceType property returns the type information of the TButton class. TButton, in this case, starts the metaclass hierarchy.

Method and Procedural Types

Method types are described by TRttiMethodType class instances, while procedural types are described by TRttiProcedureType instances. Neither TRttiMethodType, nor TRttiMethodType provides additional information and should be used only to detect the types:

{ Find and print all event types declared in the application }
for LType in LContext.GetTypes() do
  if (LType is TRttiMethodType) and EndsStr('Event', LType.Name) then
    Writeln(LType.Name);

Pointers

In Delphi, pointer types also have RTTI information emitted for them. They are represented by TRttiPointerType class instances. TRttiPointerType exposes a single property, ReferredType, which provides type information for the pointed type.

For example, given the following type:

type
  TStrPtr = ^String;

the ReferredType property provides type information for the String type that is being pointed to by the pointer type. The following code demonstrates how you can obtain this information:

var
  LContext: TRttiContext;
  LType: TRttiPointerType;

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

  LType := LContext.GetType(TypeInfo(TStrPtr)) as TRttiPointerType;
  Writeln(LType.ReferredType.Name);
end.

Note that for untyped pointer types (such as Pointer), ReferredType is nil, because it does not point to any specific type.

See Also