2010-09-28 4 views
7

Używam Delphi 6 Professional. Jestem relacje ze libraty DLL, który deklaruje typ enumberated następująco:Jak iterować zainicjowane typy wyliczeniowe za pomocą Delphi 6 i uniknąć błędu "out of bounds"?

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

Jak widać wartości inicjowany nie są ciągłe. Gdy próbuję iteracyjne typ za pomocą pętli for w następujący sposób:

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

Delphi nadal zwiększa e przez 1 każdym wywołaniu pętli i tym samym tworzy wartości numeryczne dla E, które nie są członkami wyliczeniowej typu (na przykład " 3 '), co prowadzi do błędu "poza granicami". Jak mogę iterować typ wyliczeniowy w pętli for, która generuje tylko prawidłowe wartości dla typu wyliczeniowego?

Dzięki.

Odpowiedz

13

Definiując zestaw stałych ...

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. 

i zaimplementowane jako iterator - po prostu dla zabawy ...

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. 
7

O ile pamiętam, nie ma sposobu na powtórzenie tego, jak chcesz. Jeśli wyliczanie nie jest często zmieniane, rozwiązaniem może być zadeklarowanie "tablicy indeksów", która pozwoli ci na iterację tak, jak chcesz. Sztuką jest nie iteracyjne nad wyliczeniem, ale z indeksem, który można z kolei „Convert” do ważnego elementu w ENUM:

myślę, że mogę wyjaśnić ideę lepiej w kodzie:

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; 
3

nie można

jeśli wartości są binarne try ważony za pomocą pętli while jak ten

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

end; 
4

Podczas definiowania wyliczanie

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

W rzeczywistości definiuje się typ wyliczeniowy zawierający 17 (10 USD + 1) możliwych wartości. Jest to documented.

Istnieje wiele sposobów implementacji iteracji tylko dla przypisanych stałych wyliczeniowych (zobacz inne odpowiedzi), ale w sposobie, w jaki to robisz, wykonuje się iterację z ponad 17 wartościami, których nie można zmienić.

Oto jeszcze jeden przykład iteracja który wykorzystuje fakt, że wszystkie wartości ENUMx wyjątkiem ENUM1 są potęgami 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; 
Powiązane problemy