Delphi: Углубленное исследование TRTTITypeИсточник: delphi2010 Александр Божко
TRttiType обеспечивает нас удобным интерфейсом, который позволяет получать доступ ко всей информации, связанной с типом. В большинстве случаев, как мне кажется, он интуитивно понятен и документирован. Я рекомендую открыть Rtti.pas и посмотреть описание TRttiType. В общих чертах я рассказал про TRttiType в предыдущих статьях. Подобно тому, что я начал рассказывать в предыдущей статье, если ваш тип поддерживает поля, свойства и/или методы, то существуют несколько несложных методов получения доступа к ним. Такие методы предоставляют ко всем полям, свойствам и методам, имеющим RTTI информацию, и в следующих статьях я углубленно рассмотрю TRttiField, TRttiProperty и TRttiMethod. function GetMethods: TArray<TRttiMethod>; overload; virtual; function GetFields: TArray<TRttiField>; virtual; function GetProperties: TArray<TRttiProperty>; virtual; function GetMethod(const AName: string): TRttiMethod; virtual; function GetMethods(const AName: string): TArray<TRttiMethod>; overload; virtual; function GetField(const AName: string): TRttiField; virtual; function GetProperty(const AName: string): TRttiProperty; virtual; Однако, иногда вам хочется получить доступ, к тому, что было объявлено, лишь в конкретном типе и не объявлялось в родительских типах. Это можно сделать, используя следующую функциональность: function GetDeclaredMethods: TArray<TRttiMethod>; virtual; function GetDeclaredProperties: TArray<TRttiProperty>; virtual; function GetDeclaredFields: TArray<TRttiField>; virtual; Если ваш тип унаследован, вы можете получить Основной Тип с помощью вызова свойства BaseType. program Project10; {$APPTYPE CONSOLE} uses SysUtils, RTTI; type TOneObject = Class(TObject) end; TTwoObject = Class(TOneObject) end; TThreeObject = Class(TTwoObject) end; var c : TRttiContext; t : TRttiType; begin c := TRttiContext.Create; try t := c.GetType(TThreeObject); writeln(t.Name); while Assigned(t.BaseType) do begin t := t.BaseType; writeln(t.Name); end; finally c.Free end; readln; end. Результат: TThreeObject TTwoObject TOneObject TObject Есть три набора свойств, которые дают вам больше информации о данном типе. property AsInstance: TRttiInstanceType read GetAsInstance; property IsInstance: Boolean read GetIsInstance; property AsOrdinal: TRttiOrdinalType read GetAsOrdinal; property IsOrdinal: Boolean read GetIsOrdinal; property IsSet: Boolean read GetIsSet; property AsSet: TRttiSetType read GetAsSet; Экземпляром Типов являются Классы, и тип TRttiInstanceType предоставляет свойство "MetaclassType", которое возвращает TClass для данного типа. Следующий пример показывает, как использовать этот тип для создания экземпляра объекта. program Project10; {$APPTYPE CONSOLE} uses SysUtils, RTTI; type TOneObject = Class(TObject) end; TTwoObject = Class(TOneObject) end; TThreeObject = Class(TTwoObject) end; var c : TRttiContext; t : TRttiType; o : TObject; begin c := TRttiContext.Create; try t := c.GetType(TThreeObject); o := t.AsInstance.MetaclassType.Create; Writeln(o.ClassName); o.Free; finally c.Free end; readln; end. Результат TThreeObject TRttiOrdinalType ссылается на Ординальные Типы, такие как Integer, Перечисляемые типы и т.д: TOrdType = (otSByte, otUByte, otSWord, otUWord, otSLong, otULong); ... property OrdType: TOrdType read GetOrdType; property MinValue: Longint read GetMinValue; property MaxValue: Longint read GetMaxValue; Следующий пример кода демонстрирует их поведение. program Project10; {$APPTYPE CONSOLE} uses SysUtils, RTTI,TypInfo; type TMyEnum = (enOne,enTwo,enThree); var c : TRttiContext; t : TRttiType; begin c := TRttiContext.Create; try t := c.GetType(TypeInfo(TMyEnum)); writeln(GetEnumName(TypeInfo(TOrdType),ord(t.AsOrdinal.OrdType))); writeln(t.AsOrdinal.MinValue); writeln(t.AsOrdinal.MaxValue); finally c.Free end; readln; end. Результат: otUByte 0 2 Обратите внимание, я обратился к TypInfo.pas, что бы вызвать GetEnumName(), эта, и связанная с ней функция GetEnumValue() позволяет вам работать с именами перечисляемых типов, вместо ординальных значений. program Project10; {$APPTYPE CONSOLE} uses SysUtils, RTTI,TypInfo; type TMyEnum = (enOne,enTwo,enThree); TMySet = set of TMyEnum; var c : TRttiContext; t : TRttiType; begin c := TRttiContext.Create; try t := c.GetType(TypeInfo(TMySet)); Writeln('Element Type:'); writeln(t.AsSet.ElementType.ToString); finally c.Free end; readln; end. Результат Element Type: TMyEnum Что бы быть последовательным, скажу, что тип TRttiRecordType наследуется от TRttiType, но он содержит всего одно новое свойство, ManagedFields, которому я не нашел осмысленного применения. property AsRecord: TRttiRecordType read GetAsRecord; property IsRecord: Boolean read GetIsRecord; Но не пропустите свойство IsRecord, оно очень полезно. program Project10; {$APPTYPE CONSOLE} uses SysUtils, RTTI,TypInfo; type TmyRecord = record UniStr : String; AnsiStr : AnsiString; WideStr : WideString; end; var c : TRttiContext; t : TRttiType; field : TRttiField; begin c := TRttiContext.Create; try for field in c.GetType(TypeInfo(TMyRecord)).GetFields do begin t := field.FieldType; writeln('Field:',field.Name); writeln('RttiType:',t.ClassName); if (t is TRttiStringType) then Writeln('String Kind:',GetEnumName(TypeInfo(TRttiStringKind),ord((t as TRttiStringType).StringKind))); Writeln; end; finally c.Free end; readln; end. Результат: Field:UniStr RttiType:TRttiStringType String Kind:skUnicodeString Field:AnsiStr RttiType:TRttiAnsiStringType String Kind:skAnsiString Field:WideStr RttiType:TRttiStringType String Kind:skWideString В заключение замечу, что существуют несколько других не очень значимых свойств TRttiType, но я не пытаюсь переписывать документацию, поэтому я оставлю их для самостоятельного исследования. |