2010-12-16 9 views
6

Próbuję utworzyć niestandardowy typ danych dla dni tygodnia, ale nie mogę go pobrać. Błąd kompilator mówi tak:Jak mogę używać WriteLn z typem wyliczenia?

[Błąd] hours.dpr (28): Nielegalna wpisz zapisu/writeln rachunku

program hours; 

{$APPTYPE CONSOLE} 

uses 
    SysUtils; 

type 
    TypeDay = (Sun,Mon,Tue,Wed,Thu,Fri,Sat); 

var day: TypeDay; 

begin 
    for day := Sun to Sat do 
    begin 
     writeln(day); 
    end; 
end. 

Jest w Delphi 7 w systemie Windows.

+1

Podpowiedź: co mówi kompilator? –

+7

Jesteś heretykiem. Siódmy dzień to niedziela. ;-) Ponadto: dni powszednie są wyliczeniami, które są stałymi, a nie drukowalnymi ciągami. –

+0

[Błąd] hours.dpr (28): Niedozwolony typ w oświadczeniu Write/Writeln jest błędem kompilatora – Tom

Odpowiedz

10

Tom, Writeln nie obsługuje parametru Wylicz jako. musisz wywołać funkcję Ord, aby uzyskać reprezentację porządkową. jeśli chcesz pokazać nazwy swojego TypeDay, możesz napisać taki kod.

program hours; 

{$APPTYPE CONSOLE} 

uses 
    SysUtils; 

type 
    TypeDay  = (Sun,Mon,Tue,Wed,Thu,Fri,Sat); 
const 
    TypeDayStr : Array[TypeDay] of string = ('Sun','Mon','Tue','Wed','Thu','Fri','Sat'); 

var day: TypeDay; 

begin 
    for day := Sun to Sat do 
     writeln(Ord(day)); 

    for day := Sun to Sat do 
     writeln(TypeDayStr[day]); 

    Readln; 
end. 
+0

+1 dla 'Array [TypeDay] of string'. W związku z tym musiałem usunąć własną, po prostu dumną odpowiedź. –

3

Możesz użyć RTTI do napisania wyliczonych nazw.

Oto zoptymalizowana funkcja pisałem jakiś czas temu:

program hours; 

{$APPTYPE CONSOLE} 

uses 
    SysUtils; 

function GetEnumName(aTypeInfo: pointer; aIndex: integer): PShortString; 
asm // get enumerate name from RTTI 
    or edx,edx 
    movzx ecx,byte ptr [eax+1] // +1=TTypeInfo.Name 
    mov eax,[eax+ecx+1+9+1] //BaseType 
    mov eax,[eax] 
    movzx ecx,byte ptr [eax+1] 
    lea eax,[eax+ecx+1+9+4+1] // eax=EnumType.BaseType^.EnumType.NameList 
    jz @0 
@1: movzx ecx,byte ptr [eax] 
    dec edx 
    lea eax,eax+ecx+1 // next short string 
    jnz @1 
@0: 
end; 

type 
    TypeDay = (Sun,Mon,Tue,Wed,Thu,Fri,Sat); 

var day: TypeDay; 

begin 
    for day := Sun to Sat do 
    begin 
     writeln(GetEnumName(TypeInfo(TypeDay),ord(day))^); 
    end; 
end. 

Ale ostrzegam, że ta wersja nie sprawdza, że ​​aIndex być w zasięgu.

+0

musisz żartować! pisanie kodu asemblera w Delphi? po co? – none

+0

Czy sugerujesz naukę montażu? –

+1

-1 @ A.Bouchez dlaczego nie używać tylko wbudowanych funkcji RTTI? –

2

Wyliczenia nie są ciągami, więc należy je przekonwertować.
Do konwersji można użyć funkcji GetEnumName z jednostki Delphi TypInfo jako explained at delphi.about.com.

--jeroen

16

Nie trzeba pisać Assembler do tego przeznaczonych; TypInfo zawiera wszystko, czego potrzebujesz, aby to zrobić (pobierz ciąg związany z wyliczoną wartością).

ten kod:

program hours; 

{$APPTYPE CONSOLE} 

uses 
    SysUtils, 
    TypInfo; 

type 
    TypeDay = (Sun,Mon,Tue,Wed,Thu,Fri,Sat); 

var 
    day: TypeDay; 
    Str:String; 

begin 
    for day := Sun to Sat do begin 
     Str := GetEnumName(TypeInfo(TypeDay),ord(day)); 
     writeln(Str); 
    end; 
end. 

I to jest wyjście:

alt text

Pozdrawiam.

+1

+1. Jest to właściwy sposób konwertowania wyliczenia na ciąg znaków. –

+3

Uwaga: to nie zadziała, jeśli członom enum zostaną przypisane określone wartości porządkowe, w takim przypadku kompilator usunie RTTI. (Przynajmniej tak było w przypadku każdej wersji Delphi, z której korzystałem). Nie jestem do końca pewien, dlaczego tak się dzieje. W takich sytuacjach para klucz/wartość jest rozsądnym rozwiązaniem. –

+0

@ codeelegance-> Czy możesz podać przykładowy typ tej sytuacji. Używam RTTI i tego kodu i nigdy mi się to nie udaje. –