Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
KANSoftWare

Расширение перечислений в Delphi: как добавить новые значения к наследуемым свойствам и обеспечить совместимость с базовыми типами данных.

Delphi , Синтаксис , Записи и Множества

 

В Delphi перечисления (enumerations) являются мощным инструментом для определения набора связанных значений. Однако, стандартный синтаксис Delphi не позволяет напрямую расширять существующие перечисления, добавляя новые значения. В этой статье мы рассмотрим различные подходы к решению этой задачи и предложим альтернативные решения, которые могут быть полезны в различных сценариях.

Проблема

Предположим, у нас есть базовый класс с перечислением TProviderFlag и его набором TProviderFlags:

type
  TProviderFlag = (pfInUpdate, pfInWhere, pfInKey, pfHidden);
  TProviderFlags = set of TProviderFlag;

Мы хотим добавить новое значение pfDummy к этому перечислению и создать новый набор TMyProviderFlags, который включает все значения из TProviderFlag и добавляет pfDummy:

type
  TMyProviderFlag = (pfInUpdate, pfInWhere, pfInKey, pfHidden, pfDummy);
  TMyProviderFlags = set of TMyProviderFlag;

Кроме того, мы хотим, чтобы значения TMyProviderFlag могли быть преобразованы в значения TProviderFlag и наоборот. Например:

var
  my: TMyProviderFlags;
begin
  my := [pfHidden, pfDummy];
  Table.Field.ProviderFlag := MyInstance.pfHidden; 
  if pfDummy in MyInstance then ...
end;

Решение с использованием подмножества

Один из способов решения этой задачи — использовать подмножество базового перечисления. Это позволяет добавить новые значения, но при этом значения из базового перечисления остаются совместимыми.

type
  TProviderFlag = (pfInUpdate, pfInWhere, pfInKey, pfHidden);
  TProviderFlags = set of TProviderFlag;

const
  {$R-}  // отключаем проверку диапазона
  pfDummy = Succ(pfHidden);

type
  TMyProviderFlag = pfInUpdate .. pfDummy;
  TMyProviderFlags = set of TMyProviderFlag;

В этом примере TMyProviderFlag является подмножеством TProviderFlag, и мы можем преобразовывать значения между ними:

var
  my: TMyProviderFlags;
begin
  my := [pfHidden, pfDummy];
  Table.Field.ProviderFlag := TProviderFlag(my[0]); 
  if pfDummy in my then ...
end;

Альтернативное решение с использованием рекорда

Если базовое перечисление не может быть изменено, можно использовать запись (record) для создания расширенного типа:

type
  TBaseEnum = (beOne, beTwo, beThree);

type
  TExtEnum = packed record
  strict private
    Value: Byte;
  public
    class operator Implicit(const ABaseEnum: TBaseEnum): TExtEnum;
    class operator Implicit(const AExtEnum: TExtEnum): TBaseEnum;
  end;

{$IF SizeOf(TBaseEnum) <> SizeOf(TExtEnum)}
{$MESSAGE Fatal 'SizeOf(TBaseEnum) <> SizeOf(TExtEnum)'}
{$ENDIF}

const
  beFour: TExtEnum = (Value: Succ(Ord(beThree)));

{ TExtEnum }

class operator TExtEnum.Implicit(const AExtEnum: TExtEnum): TBaseEnum;
begin
  if InRange(AExtEnum.Value, Ord(Low(TBaseEnum)), Ord(High(TBaseEnum))) then
    Result := TBaseEnum(AExtEnum.Value)
  else
    raise EConvertError.Create('TExtEnum cannot be converted to TBaseEnum.');
end;

class operator TExtEnum.Implicit(const ABaseEnum: TBaseEnum): TExtEnum;
begin
  Result.Value := Ord(ABaseEnum);
end;

Этот подход позволяет создать расширенный тип TExtEnum, который включает все значения из TBaseEnum и добавляет новые. Преобразования между TBaseEnum и TExtEnum выполняются через операторы приведения типа (implicit).

Пример использования

var
  b: TBaseEnum;
  x: TExtEnum;
begin

  b := beOne;
  x := b; // fine
  b := x; // fine

  x := beOne; // fine
  x := beTwo; // fine
  x := beThree; // fine
  x := beFour; // fine

  x := beOne; // fine
  b := x; // fine

  b := beFour; // run-time error

  x := beFour; // fine
  b := x; // run-time error

end;

В этом примере значения TBaseEnum и TExtEnum могут быть преобразованы друг в друга, но при попытке преобразовать значение, выходящее за пределы TBaseEnum, возникает исключение.

Заключение

Расширение перечислений в Delphi не является стандартной задачей, но существуют различные подходы к решению этой проблемы. В зависимости от конкретных требований и ограничений, можно использовать подмножества или записи для создания расширенных типов. Каждый из этих подходов имеет свои преимущества и недостатки, и выбор метода зависит от конкретной ситуации и предпочтений разработчика.

Создано по материалам из источника по ссылке.


Комментарии и вопросы

Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS




Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.


:: Главная :: Записи и Множества ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-12-22 20:14:06
2025-05-01 10:28:04/0.0036580562591553/0