Как повторить инициализированные перечисленные типы с Delphi 6 и избегайте ошибки «вне границ»?

StackOverflow https://stackoverflow.com/questions/3817565

Вопрос

Я использую Delphi 6 Professional. Я взаимодействую с DLL Libraty, которая объявляет девверованный тип следующим образом:

TExtDllEnum = (ENUM1 = $0, ENUM2 = $1, ENUM3 = $2, ENUM4 = $4, ENUM5 = $8, ENUM6 = $10);

Как вы можете видеть, инициализированные значения не являются смежными. Если я стараюсь повторять тип, используя A для цикла следующим образом:

var
    e: TExtDllEnum;
begin
    for e := Low(TExtToDllEnum) to High(TExtToDllEnum) do
    ... // More code
end;

Delphi все еще увеличивается на 1 каждую вызов цикла и тем самым создает числовые значения для E, которые не являются членами перечисленного типа (например, «3»), а также приводят к ошибке «вне оценки». Как я могу перечислить перечисленный тип в цикле для цикла, который генерирует только допустимые значения для перечисленного типа?

Спасибо.

Это было полезно?

Решение

Определив набор констант ...

type
  TExtDllEnum = (ENUM1 = $0, ENUM2 = $1, ENUM3 = $2, ENUM4 = $4, ENUM5 = $8, ENUM6 = $10);

const
  CExtDllEnumSet = [ENUM1, ENUM2, ENUM3, ENUM4, ENUM5, ENUM6];


var
  e: TExtDllEnum;
begin
  e := Low(TExtDllEnum);
  while e <= High(TExtDllEnum) do
  begin
    if e in CExtDllEnumSet then 
      WriteLn(Ord(e));

    Inc(e);
  end;

  ReadLn;
end.

И реализован как итератор - просто для удовольствия ...

type
  TExtDllEnum = (ENUM1 = $0, ENUM2 = $1, ENUM3 = $2, ENUM4 = $4, ENUM5 = $8, ENUM6 = $10);
const
  CExtDllEnumSet = [ENUM1, ENUM2, ENUM3, ENUM4, ENUM5, ENUM6];

type
  TMyIterator = class
  private
    FValue: TExtDllEnum;
  public
    constructor Create;
    function Next: TExtDllEnum;
    function HasNext: Boolean;
  end;

  constructor TMyIterator.Create;
  begin
    FValue := Low(TExtDllEnum);
  end;

  function TMyIterator.HasNext: Boolean;
  begin
    Result := FValue <= High(TExtDllEnum);
  end;

  function TMyIterator.Next: TExtDllEnum;
  begin
    Result := FValue;

    repeat
      Inc(FValue);
    until (FValue in CExtDllEnumSet) or (FValue > High(TExtDllEnum))
  end;

var
  MyIterator: TMyIterator;
begin
  MyIterator := TMyIterator.Create;

  while MyIterator.HasNext do
    WriteLn(Ord(MyIterator.Next));

  MyIterator.Free;

  ReadLn;
end.

Другие советы

Насколько я могу вспомнить, нет никакого способа потерять то, как вы хотите. Если перечисление не изменяется часто, обходной путь может заключаться в том, чтобы объявить «индексный массив», который позволит вам повторить, как вы хотите. Хитрость - это вы не повторяете перечисление, но по индексу, который вы можете в свою очередь, «преобразовать» на действительный элемент в Enum:

Я думаю, что могу объяснить идею лучше в коде:

const
  ExtDllEnumElements = 6;
  EnumIndexArray: array[0..ExtDllEnumElements - 1] of TExtDllEnum = (ENUM1, ENUM2, ENUM3, ENUM4, ENUM5, ENUM6);
var
  I: Integer;
begin
  for I := Low(EnumIndexArray) to High(EnumIndexArray) do
    WhateverYouWantWith(EnumIndexArray[I]);
end;

Когда вы определяете перечисление

TExtDllEnum = (ENUM1 = $0, ENUM2 = $1, ENUM3 = $2, ENUM4 = $4, ENUM5 = $8, ENUM6 = $10);

Вы на самом деле определяете тип перечисления, состоящий из 17 (10 + 1) возможных значений. То есть документированный.

Есть много способов реализации итерации по сравнению с назначенными константами перечисления (см. Другие ответы), но как вы делаете это, вы используете его, вы выполняете его, вы выполняете более 17 значений, и это нельзя изменить.

Вот еще один пример итерации, который использует тот факт, что все значения Enumx, кроме Enum1, являются полномочиями 2:

type
  TExtDllEnum = (ENUM1 = $0, ENUM2 = $1, ENUM3 = $2,
                 ENUM4 = $4, ENUM5 = $8, ENUM6 = $10);
var
    e: TExtDllEnum;

begin
  e:= Low(TExtDllEnum);
  repeat
    [..]
    if e = ENUM1 then e:= ENUM2
    else if e = High(TExtDllEnum) then Break
    else e:= e shl 1;
  until False;
end;

Вы не можете

Если значения являются бинарными взвешенными, попробуйте использовать цикл A, как это

var
    e: TExtDllEnum;
begin
    e := 0;
    While e <= High(TExtToDllEnum) do
    begin
        ... // More code
        e := Power(2, e);
    end;

end;
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top