Застосування перелічуваних типів delphi

Отже, що таке RTTI.
Runtime Type Information або сокрашенія RTTI (інформація про типи часу виконання) -це дані, що генеруються компілятором Delphi про об'єкти програми. RTTI є можливість мови, що забезпечує додаток інформацією про об'єкти (ім'я, розмір екземпляра, покажчики на клас-предок, ім'я класу і т. Д.) І про простих типах під час роботи програми. Delphi, наприклад, використовує RTTI для доступу до значень властивостей компонент, що зберігаються і зчитувальних з dfm-файлів і відображення їх в Object Inspector.






Основоположні визначення типів, основні функції та процедури для роботи з runtime інформацією знаходяться в модулі TypInfo. Цей модуль містить дві фундаментальні структури для роботи з RTTI - TTypeInfo і TTypeData (типи вказівників на них - PTypeInfo і PTypeData відповідно). Спробуємо використовувати їх на конкретному прикладі.
Припустимо, нам необхідно сформувати рядок-запит до того ж Google, щоб отримати доступ до API. Що ми можемо почерпнути з документації по ClientLogin?
1. Це те, що такі параметри як AccountType і Service можуть приймати цілком конкретні значення, які можна представити у вигляді двох перелічуваних типів даних:

type TAccountType = (GOOGLE, HOSTED, HOSTED_OR_GOOGLE); type TServices = (xapi, analytics, apps, gbase, jotspot, blogger, print, cl, codesearch, cp, writely, finance, mail, health, local, lh2, annotateweb, wise , sitemaps, youtube);

2. Відповідь сервера також може містити обмежену кількість значень (кодів) помилок і 1 значення ( «Ok») при успішній аутентифікації. Отже отримаємо ще один тип даних:

type TErrorCodes = (Ok, BadAuthentication, NotVerified, TermsNotAgreed, CaptchaRequired, Unknown, AccountDeleted, AccountDisabled, ServiceDisabled, ServiceUnavailable);

Тепер, коли все перераховуються типи даних визначені, виникає просте запитання «Що далі?». Як би ми вчинили, наприклад, при формуванні рядка запиту, якщо б абсолютно нічого не знали про RTTI і модуль TypInfo зокрема?






Як мінімум, ми б організували, щось на зразок цього:

var Param: string; AccType: TAccountType; begin case AccType of GOOGLE: ParamStr: = 'щось там-AccauntType = GOOGLE'; HOSTED: ParamStr: = 'щось там-AccauntType = HOSTED'; HOSTED_OR_GOOGLE: ParamStr: = 'щось там-AccauntType = HOSTED_OR_GOOGLE'; end; end;

Приблизно те ж саме і щодо TServices. Чи буде цей код працювати? Звичайно буде ... куди він нафіг дінеться. Але ж можна зробити і по іншому.
У модулі TypInfo визначений наступний метод:

function GetEnumName (TypeInfo: PTypeInfo; Value: Integer): string;

Дозволяє отримати значення перераховується типу у вигляді простої рядки. Перший параметр - покажчик на запис TTypeInfo. другий - порядковий номер значення в перераховувати типі даних.
Тобто виконавши наступний код:

Ми отримаємо повідомлення, що містить рядок «HOSTED». Тепер застосувавши цей метод, ми можемо скоротити код представлений вище за все до одного рядка:

var Param: string; AccType: TAccountType; begin ParamStr: = 'щось там-AccountType =' + GetEnumName (TypeInfo (TAccountType), ord (AccType)); end;

Або, якщо Ви використовуєте якийсь шаблон для формування рядка, то так:

var Param: string; AccType: TAccountType; begin ParamStr: = Format (Shablon, [GetEnumName (TypeInfo (TAccountType), ord (AccType)]); end;

Тепер, припустимо, що ми сформували рядок запиту, відправили запит на сервер і отримали назад відповідь, що містить «Ок» або строковий код помилки. І нам необхідно якоїсь змінної типу TErrorCodes привласнити значення відповідно до відповіддю. Знову ж таки, як би ми поступили без знань про TypInfo, отримавши, наприклад код помилки «NotVerified»? Хтось почав би розписувати купу if..then..else, або використовувати метод AnsiIndexStr з модуля StrUtils, щоб потім порівняти отримане значення зі значенням порядкового типу приблизно так:

var ErrCode: TErrorCodes; begin ErrCode: = TErrorCodes (AnsiIndesStr (MassivStrok, "NotVerified")); end;

Знову ж працювати все буде, але навіщо нам тягати за собою зайвий модуль StrUtils в uses, коли у нас вже є TypInfo? Скористаємося ще одним методом для роботи з перерахованими типами:

function GetEnumValue (TypeInfo: PTypeInfo; const Name: string): Integer;

Метод повертає порядковий номер значення перераховується типу. На вхід подається все той же покажчик на TTypeInfo і значення порядкового типу у вигляді рядка. Якраз те, що нам і треба. В результаті застосування GetEnumValue наведений вище фрагмент коду можна змалювати таку картину:

08.05.02
UPDATE: невелике доповнення - функції GetEnumValue і GetEnumName не генерують виключення у випадках, якщо ви задасте другим параметром невірну рядок або неіснуючий індекс елемента. У першому випадку GetEnumValue просто поверне вам значення 255, а GetEnumName незрозумілу рядок.

UPDATE. Якщо елементи перераховується типу починаються не з 0, як зазвичай, а, наприклад, з 3, то отримуємо при компіляції помилку «ERROR:« E2134: Type 'TMyEnum' has no typeinfo »»







Схожі статті