Перечислимые типы

Для кого написана эта страница
Представленный материал предназначен строго для трёх категорий читателей, каждая из которых преследует свои цели при работе с перечислимыми типами в среде Delphi (Embarcadero Delphi / Object Pascal):
- Начинающий дельфист (стажёр / студент / любитель): вы пишете свой первый небольшой проект — консольное приложение, утилиту или простую форму. Ваша главная цель — разобраться, как enum делает код понятнее, и не совершить типичных ошибок (например, случайно присвоить недопустимое значение). Критерий выбора для вас — простота и наглядность.
- Корпоративный разработчик Win32 / VCL: вы поддерживаете или создаёте коммерческое приложение с десятками модулей. Ваша задача — добиться, чтобы перечислимые типы работали в связке с case-операторами, не вызывали сюрпризов с рантайм-приведением и повышали читаемость кода для вашей команды. Критерии выбора — типизированная безопасность и строгость компилятора.
- Автор публичных библиотек / компонентов: вы проектируете API для других разработчиков. Вам критична совместимость с будущими версиями Delphi, возможность добавления новых значений без поломки существующего кода клиентов. Критерий выбора — управляемое расширение (scoped enum или использование множеств).
Какие задачи решают перечислимые типы
Для каждой группы цели различаются, поэтому мы разберём их отдельно.
Для начинающих: организация набора констант
Когда вы только осваиваете Delphi, вы сталкиваетесь с проблемой «магических чисел». Вместо кода if State = 0 then вы можете написать if State = TStatus.Active then. Начинающим подходит самый базовый вариант классического перечислимого типа без модификаторов:
type
TWeekDay = (Monday, Tuesday, Wednesday, Thursday, Friday);
var
Day: TWeekDay;
begin
Day := Tuesday;
case Day of
Monday: WriteLn('Старт недели');
Friday: WriteLn('Почти выходные');
end;
end.Этот вариант выбирают, когда количество значений не превышает 256 и не требуется дополнительной безопасности на этапе компиляции.
Для корпоративных разработчиков: строгая типизация и защита от ошибок
Крупные проекты страдают от случайного присвоения значений типа «integer» вместо enum. Здесь нужны строго типизированные перечислимые типы с указанием директивы {$SCOPEDENUMS ON} или синтаксис type TMyEnum = (Value1, Value2) <Delphi 2010+>.
- Выбор: используйте
Type TStatus = (stNone, stActive, stInactive);во всех ваших модулях. - Критерий: при обращении из другого модуля нужно писать
TStatus.stActive, что исключает коллизию имён в большом проекте. - Когда не подходит: если вы работаете с старым кодом на Delphi 7, где скаупинг не поддерживается — тогда остаётся только классический enum с префиксами (например,
stActive).
Для авторов библиотек: расширяемость и обратная совместимость
Вы пишете компонент, который будут наследовать другие. Если вы добавите новое значение в середину существующего перечисления, то сломаете ord-смещения у всех клиентов. Вам нужен перечислимый тип с явным заданием числовых констант:
type
TVersionFlag = (
vfNone = 0,
vfAlpha = 1,
vfBeta = 2,
vfRc = 4, // резерв для будущих значений
vfFinal = 8
);Для кого это: только для разработчиков, которые распространяют свой код как сторонний пакет. Каждое новое значение должно добавляться как степень двойки, чтобы сочетать флаги через множества (set of).
Как выбрать свой вариант перечислимого типа
- Вы начинающий — берите классический enum без скаупинга. Он проще для чтения и не требует настройки компилятора.
- Вы пишете средний Win32-проект (до 50 модулей) — включите
{$SCOPEDENUMS ON}в начале каждого файла. Это даст автодополнение в IDE и предотвратит случайное использование зарезервированных имён. - Вы разрабатываете FireMonkey-приложение с многопоточностью — обязательно добавьте
packed enum, если размер структуры критичен. Но помните: для большинства задачpackedне нужен. - Вы хотите, чтобы ваш enum можно было сохранять в INI-файл или JSON — используйте RTTI-функции (
TypInfo). Тогда при смене значений потребуется лишь модифицировать перечисление, а строковое представление останется стабильным. - Вы автор библиотеки — каждому значению присвойте явное число, оставляйте зазоры между значениями для будущего расширения и документируйте, что «значения 3,5–7 зарезервированы».
Типичные ошибки по сегментам аудитории
- Начинающий: забывает, что
Succ(Enum)иPred(Enum)могут выйти за границы — проверяйте на равенствоHigh(Enum). - Корпоративный разработчик: использует
ord(EnumValue)а потом сравнивает с целым — нарушается инкапсуляция. Правильно:caseпо самому enum, а не поord. - Автор библиотеки: добавляет новое значение в конец перечисления без явных чисел — клиенты получат баги сериализации.
Заключение под ваши задачи
Если вы — новичок, начните с простого: type TDirection = (Left, Right, Up, Down);. Никаких дополнительных настроек не требуется — компилятор Delphi по умолчанию использует классический enum. Код сразу станет читаемее, и вы избежите бинарных констант.
Если вы — разработчик в команде, требуйте от коллег включения {$SCOPEDENUMS ON} в общем репозитории. Это окупится через месяц поддержки.
Если вы — создатель компонентов, используйте явные числовые значения и пишите документацию в комментариях над типом.
Помните: перечислимый тип в Delphi — это не просто синтаксический сахар, а инструмент, который выбирают под реальную аудиторию вашего кода.
Добавлено: 27.04.2026
