単純型の情報
RTTI の操作 への移動
はじめに
Delphi の型は、単純型と構造化型の 2 種類に大きく分けることができます。型情報の点では、通常、単純型は構造化型よりずっと少ない情報しか持ちません。
取得した TRttiType がある型を表しているかどうかを確認するには、TRttiType.TypeKind プロパティを使用します。この値には、実際の型の種類が示されています。もう 1 つ、次のように is
演算子を使用して、TRttiType インスタンスの実際のクラス型を判断するという方法もあります。
{ 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());
}
}
この例では、アプリケーションおよびそのパッケージの中で宣言されている文字列型だけが表示されます。
順序型
順序型の情報を持つのは TRttiOrdinalType クラス インスタンスです。TRttiOrdinalType は、MinValue や MaxValue や OrdType といった、順序型に固有の情報にアクセスするためのプロパティを公開しています。
次の例では、アプリケーションおよびそのパッケージで定義された順序型をすべて列挙し、そのプロパティをコンソールに出力しています。
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);
}
}
列挙型も順序型とみなされるため、この例では列挙型の情報も出力されることに注意してください。
64 ビット整数型
64 ビット整数の基底型は順序型と同じではありません。そのため、64 ビット整数の情報は TRttiInt64Type クラスが保持します。TRttiInt64Type は、TRttiOrdinalType と同様に、MinValue プロパティと MaxValue プロパティを公開しています。
次の例では、アプリケーションおよびそのパッケージで宣言された 64 ビット整数をすべて列挙しています。
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);
}
}
浮動小数点型
浮動小数点型の情報を持つのは TRttiFloatType クラス インスタンスです。TRttiFloatType が公開しているプロパティは FloatType の 1 つだけです。このプロパティによって浮動小数点型のサブタイプを特定することができます。
次の例では、宣言された浮動小数点型のうちサブタイプが Double であるものをすべて出力しています。
for LType in LContext.GetTypes() do
if (LType is TRttiFloatType) and (TRttiFloatType(LType).FloatType = ftDouble) then
Writeln('Type name:', LType.Name);
出力結果には、Double 型自体と、倍精度実数型である Real 型、そして System ユニットで宣言された一連の日時型が含まれます。
集合型
集合型の情報を持つのは TRttiSetType クラス インスタンスです。TRttiSetType が公開しているプロパティは ElementType の 1 つだけであり、このプロパティは集合に含まれる要素の型情報を提供します。たとえば、集合が次のように定義されているとします。
type
TByteSet = set of Byte;
次のコードを実行すると、集合要素の型の名前(ここでは 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.
列挙型
列挙型の情報を持つのは TRttiEnumerationType クラス インスタンスです。TRttiEnumerationType は、TRttiOrdinalType から派生した型で、UnderlyingType という新しいプロパティが追加されています。UnderlyingType は、この列挙型で使われている実際の列挙型の型情報を提供します。
次のような 2 つの列挙型があるとします。1 つは新しいもの、もう 1 つは標準の TSeekOrigin 列挙型のエイリアスです。
type
TNewEnum = (neOne, neTwo, neThree);
TOtherEnum = type TSeekOrigin;
次のコードを実行すると、この 2 つの型のベースとなる型の名前が出力されます。
{ 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);
新しく宣言した列挙型(TNewEnum など)の場合には、UnderlyingType プロパティがその列挙型自体の型情報を返すことに注意が必要です。エイリアスの付けられた強い型(TOtherEnum など)の場合、UnderlyingType はその型の型情報を返します。
文字列
文字列型の情報を持つのは TRttiStringType クラス インスタンスです。TRttiStringType が公開しているプロパティは StringKind の 1 つだけです。このプロパティによって実際の文字列型を特定することができます。文字列型は次のいずれかになります。
- 短い文字列
- ANSI 文字列
- ワイド文字列
- Unicode 文字列
次の例では、アプリケーションおよびそのパッケージで宣言された ANSI 文字列型をすべて出力しています。
for LType in LContext.GetTypes() do
if (LType is TRttiStringType) and (TRttiStringType(LType).StringKind = skAnsiString) then
Writeln(LType.Name);
Rtti ユニットでは、AnsiString 型のために特別に TRttiAnsiStringType クラスを定義しています。TRttiAnsiStringType は TRttiStringType から派生した型で、CodePage という新しいプロパティが追加されており、このプロパティを使って AnsiString のコード ページを取得することができます。
次の例では、RawByteString 型のコード ページを出力しています。
{ 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);
クラス参照(メタクラス)
クラス参照型の情報を持つのは TRttiClassRefType クラス インスタンスです。TRttiClassRefType を使用すると、メタクラスが表す階層の基底として使われるクラス型を取得することができます(InstanceType プロパティを使用します)。TRttiClassRefType の MetaclassType を使ってメタクラス自体に直接アクセスすることもできます。
次の例では、アプリケーションおよびそのパッケージで宣言されたメタクラス型をすべて出力しています。これは 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.
上記の例で出力される情報をよく理解するために、次の型定義を考えてみます。
type
TButtonClass = class of TButton;
この型の場合、MetaclassType プロパティがメタクラス自体を返すのに対し、InstanceType プロパティは TButton クラスの型情報を返します。この例では TButton がメタクラス階層の始点となっています。
メソッド型と手続き型
メソッド型の情報は TRttiMethodType クラス インスタンスが、手続き型の情報は TRttiProcedureType クラス インスタンスが保持します。TRttiMethodType も TRttiProcedureType もそれ以上の情報は持たないため、型を判断するためだけに使用してください。
{ 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);
ポインタ
Delphi では、ポインタ型の場合も RTTI 情報が出力されます。ポインタ型を表すのは TRttiPointerType クラス インスタンスです。TRttiPointerType が公開しているプロパティは ReferredType の 1 つで、このプロパティはポインタが指す先の型の型情報を提供します。
たとえば、次のような型があるとします。
type
TStrPtr = ^String;
ReferredType プロパティは、ポインタ型が指している String 型の型情報を提供します。次のコードは、この情報をどう取得できるかを示すものです。
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.
型が指定されていないポインタ型(Pointer など)の場合、具体的な型を指していないため、ReferredType は nil になります。