![]() |
Delphi-Version: 7
Array [Auszählungstyp] of irgendwas?
Ich habe eine Typdefinition:
Delphi-Quellcode:
und ein String-Array, in denen die Werte des Typs beschrieben werden:
TEnum = (Anfang = 1, Mitte = 3, Ende = 5);
Delphi-Quellcode:
Wenn ich die Leerstring-Einträge weglasse, mault der Compiler (Anzahlen stimmen nicht überein). Warum?
g_TEnumNames = Array[TEnum] of String =
('Anfang', '', 'Mitte', '', 'Ende'); Noch extremer wird es (finde ich jedenfalls), wenn ich über den Typ iteriere:
Delphi-Quellcode:
Die Schleife wird fünfmal durchlaufen, obwohl der Typ nur mit drei Werten definiert ist.
pos: TEnum;
... for pos := Low(TEnum) to High(TEnum) do TuIrgendwasMit(pos, g_TenumNames[pos]); Gibt es eine saubere Methode, einen Typ aus drei Werten tatsächlich nur aus drei Werten bestehen zu lassen (und trotzdem eine selbstgewählte Numerierung beizubehalten)? |
AW: Array [Auszählungstyp] of irgendwas?
Die einzige Möglichkeit, die mir einfällt, wäre:
Delphi-Quellcode:
Anders würde der Compiler eine Sukkzessor-Funktion auf TEnum auch nicht umsetzen.
Type
TEnum = (Anfang = 1, Mitte = 3, Ende = 5); Function NextEnum (e: TEnum) : TEnum; Begin case e of Anfang : Return Mitte; Mitte : Return Ende; else Raise EInvalidArgument.Create; // K.A. wie das in Delphi heißt. End End; ... e := Anfang; While e <> Ende Do begin e :=NextEnum(e); end; Wieso willst Du den Enum-Elementen eigentlich nicht fortlaufende Werte geben? Wenn Du gleichzeitig iterieren musst, könntest Du doch eine Abbildungsfunktion schreiben, also z.B. so:
Delphi-Quellcode:
Type
TEnum := (Anfang, Mitte, Ende); Const EnumWerte : Array [TEnum] Of Integer = (1,3,5); EnumNamen : Array [TEnum] Of String = ('Anfang','Mitte','Ende'); |
AW: Array [Auszählungstyp] of irgendwas?
Ist auch richtig so, denn ein Enum hat nunmal nur einen Anfang und ein Ende ... er kennt kein "das dazwischen gibt es nicht"
Und weißt du was noch schön ist? Bei Enums mit vorgabewerten, wird keine RTTI über die Namen angelegt, weswegen du auch nicht die Enum-Werte in ihre "Strings" via RTTI übersetzen kannst und somit auch da nicht prüfbar ist, was es gibt. |
AW: Array [Auszählungstyp] of irgendwas?
Also in neueren Delphis gibt es ja for-in-Schleifen, damit sollte – vermutlich – zumindest das Problem mit dem Iterieren gelöst sein.
[roter Kasten] Denke auch, die zweite Variante wäre am besten. |
AW: Array [Auszählungstyp] of irgendwas?
Delphi-Quellcode:
läßt sich via
Type TEnum = (Anfang, Mitte, Ende);
![]() ![]() Also zusammen mit
Delphi-Quellcode:
.
Const EnumWerte : Array [TEnum] Of Integer = (1,3,5);
Bei neueren Delphis könnte man die Werte auch via Attribut an die Typ-Definition hängen und man könnte da auch andere/alternative "Namen" via Attribut angeben. (wenn man nicht GetEnumName nimmt, sondern es dort selber aussliest) |
AW: Array [Auszählungstyp] of irgendwas?
Vielen Dank erstmal für die Anregungen. Ich werde mal versuchen, ob ich mit "GetEnumName" weiterkomme (Namen wären mir auch lieber als die Nummern).
Ansonsten finde ich Furtbichlers zweiten Vorschlag praktikabel, das wird "Plan B" |
AW: Array [Auszählungstyp] of irgendwas?
Und nochmal ein kleines Beispiel, zu dem "warum" es nicht geht.
Das ist wie beim Boolean, welcher auch nicht "nur" zwei Zustände kennt -> ![]()
Delphi-Quellcode:
type
TMyEnum = (Anfang = 1, Mitte = 3, Ende = 5); var MyEnum: TMyEnum; MyEnum := TMyEnum(2); // hier ginge auch 0 bis 255 (oder größer, jenachdem wie $MINENUMSIZE definiert und wie groß der größte Wert in der Debinition ist) Case MyEnum of Anfang: ShowMessage('Anfang ' + IntToStr(Ord(MyEnum))); Mitte: ShowMessage('Mitte ' + IntToStr(Ord(MyEnum))); Ende: ShowMessage('Ende ' + IntToStr(Ord(MyEnum))); Else ShowMessage('blubb ' + IntToStr(Ord(MyEnum))); End; |
AW: Array [Auszählungstyp] of irgendwas?
@Himitsu:
Das ist der Grund weshalb bei der Geschichte das Zweifeln anfängt. Da ist eine Variable vom Typ T. Bisher bin ich (in Analogie zu C#) davon ausgegangen, dass die Variable wirklich vom Typ T ist - Der "else" (bzw. "default:") würde von einem Quellcodeanalyzer bemängelt werden, weil er nie ausgeführt werden könnte. Bedeutet das nun, dass eine Methode, der ein T-Parameter übergeben wird, nun überprüfen muss, ob der Parameter wirklich ein T ist? Der GetEnumName funktioniert leider in meinem Delphi nicht, (eben weil keine RTTI für den Enum-Typ vorhanden ist). @ Namenloser: Roter Kasten? @Furtbichler: Plan B funktioniert (logisch). Der Grund für die Numerierung ist der, dass die Klassen, in denen der Typ enthalten ist in eine Datenbank persistiert werden und es denkbar ist, dass es eine Erweiterung gibt. Andererseits möchte ich eine Kontrolle über die Reihenfolge der Werte behalten. Aussehen tut es jetzt so:
Delphi-Quellcode:
Nochmals vielen Dank
g_EreignisTypNummer: Array[TEreignisTyp] of Integer = (1,2,3,4,10,11,12,13,14);
g_EreignisTypName: Array[TEreignisTyp] of String = (...); ... for ereignis := Low(TEreignisTyp) to High(TEreignisTyp) do begin ereignisNr := g_EreignisTypNummer[ereignis]; TuIrgendwasMit(ereignis, ereignisNr, EreignisTypName[ereignis]); end; ... query.Parameters.ParamValues['EreignisTyp']:= g_EreignisTypNummer[m_EreignisTyp]; |
AW: Array [Auszählungstyp] of irgendwas?
Wenn du unbedingt den Enumwerten eine Zahl zuordnen musst dann geht das so:
Delphi-Quellcode:
Um jetzt von einem TEnumError zu der Beschreibung zu kommen verwendet man eine For-Schleife über das Array ErrorInfo und holt sich den passenden txt raus.
TEnumErrors = (NOERROR=0, FILEERROR=104, NETERROR=200, ...);
TErrorInfo = record err: TEnumErrors; txt: String; end; const ErrorInfo: array[0..2] of TErrorInfo = ( (err:NOERROR; txt:"kein Fehler"), (err:FILEERROR; txt:"Dateifehler"), (err:NETERROR; txt:"Netzwerkfehler") ); Der Code dazu spare ich mir -> Hausaufgabe. Man kann den Record auch um weitere Infos erweitern wie z.B. die Schwere des Fehlers. |
AW: Array [Auszählungstyp] of irgendwas?
Zitat:
|
AW: Array [Auszählungstyp] of irgendwas?
@Mikkey: Der Delphi-Compiler bemängelt auch (an vielen Stellen) derartige Werte, welche sich außerhalb der Definition befinden,
allerdings "warnt" er da nur und läßt es dennoch zu und ich weiß jetzt nicht, in wie weit das beim ELSE zutrifft. Hab das z.B. ausgenutzt, um eine Fremdkomponente um ein paar States zu erweitern.
Delphi-Quellcode:
TIEMouseInteractVtItems ist ein Enum, welcher den Zustand der Input-Verarbeitung angibt
const
miImageMove = Succ(High(TIEMouseInteractVtItems)); miImageZoom = Succ(miImageMove); und bei dem hab ich zwei eigene Zustände angehängt, welche ich dann selber behandle. (wobei ich mir diese Warnungen ausgeblendet hab >
Delphi-Quellcode:
)
{$WARNINGS OFF}
Enums und Sets besitzen leider keine Vererbung. Und im Speicher sind nunmal auch die anderen Werte möglich.
Delphi-Quellcode:
type
TMyEnum = (Anfang = 1, Mitte = 3, Ende = 5); TMySet = set of TMyEnum; var MyEnum: TMyEnum; MySet: TMySet; MySet := [TMyEnum.Anfang..TMyEnum.Ende]; // [Anfang..Ende]; for MyEnum in MySet do case MyEnum of Anfang: ShowMessage('Anfang'); Mitte: ShowMessage('Mitte'); Ende: ShowMessage('Ende'); else ShowMessage(IntToStr(Ord(MyEnum))); end;
Delphi-Quellcode:
MySet := [TMyEnum.Anfang..TMyEnum.Ende]; // [Anfang..Ende];
Exclude(MySet, TMyEnum.Mitte); if TMyEnum.Anfang in MyEnum then ; // hier mal mit dem Debugger nachsehn, was der als Inhalt für MyEnum angibt |
AW: Array [Auszählungstyp] of irgendwas?
Zitat:
Delphi-Quellcode:
type
TEnum = (Anfang = 1, Mitte = 3, Ende = 5); var pos: TEnum; begin pos := TEnum(2); pos := TEnum(4); end. Zwar gibt es im Source dann keine Identifier mehr, die diese Werte darstellen, aber es sind immer noch gültige Werte für TEnum. |
AW: Array [Auszählungstyp] of irgendwas?
Und warum nicht so?
Delphi-Quellcode:
Das hat auch den Vorteil, dass man auch unterschiedliche Datentöpfe mit unterschiedlichen Kennziffern (für die gleiche Aussage) haben kann, die im Programm aber komplett gleich behandelt werden.
type
TEnum = ( Anfang, Mitte, Ende ); const g_TEnumNames = Array[TEnum] of String = ( 'Anfang', 'Mitte', 'Ende' ); // Wobei dieses nur in der Datenschicht deklariert werden muss, da es nur dort benötigt wird g_TEnumValues = array[TEnum] of integer = ( 1, 3, 5 );
Delphi-Quellcode:
und
unit LayerDataInhouse;
interface procedure Save( AEnum : TEnum ); implementation const C_TEnumValues : array[TEnum] of integer = ( 1, 3, 5 ); procedure Save( AEnum : TEnum ); begin Save( C_TEnumValues[AEnum] ); end; end.
Delphi-Quellcode:
unit LayerDataSomethingDifferent;
interface procedure Save( AEnum : TEnum ); implementation const C_TEnumValues : array[TEnum] of integer = ( 25, 3, 9 ); procedure Save( AEnum : TEnum ); begin Save( C_TEnumValues[AEnum] ); end; end. |
AW: Array [Auszählungstyp] of irgendwas?
@Sir Rufo:
Dass solche Verpackungsmöglichkeiten bestehen, ist schon klar. Es ging mir hauptsächlich um die Verwendung von Arrays per Aufzählungstyp. @Himitsu: Was ich meine ist so etwas:
Code:
So etwas bringt beim C#-Compiler eine Warnung "line following 'return b;' is dead code". Tools zur Quelltextanalyse maulen noch weit mehr an, z.B. wenn Referenzen mit null, andere Daten mit ihrem Defaultwert initialisiert werden.
{
if (a<b) return a; else return b; return 0; } Mir macht aktuell aber noch etwas Anderes Probleme, der Code steht mir aktuell nicht zur Verfügung, aber ich gebe das mal sinngemäß wieder:
Delphi-Quellcode:
Greife ich nun im Code auf das Array mit den Werten des Typs zu, erhalte ich die falschen Einträge:
TEreignis = (EEins, EZwei, EDrei, EVier, EFuenf,ESechs, ESieben, EAcht, ENeun);
... g_EreignisTypName: Array[TEreignisTyp] of String = ( 'the', 'quick', 'brown', 'fox', 'jumps' 'over' 'the', 'lazy' 'dog');
Delphi-Quellcode:
Dann steht in s1 'dog' und in s2 'lazy'. Tatsächlich sind lt. Debugger die Arraypositionen 6/7 und 8/9 vertauscht. Das gesamte Array wird im Tooltip aber in der richtigen Reihenfolge gezeigt.
s1 := g_EreignisTypName[EAcht];
s2 := g_EreignisTypName[ENeun]; Auch als Test zugewiesene Integer per 'EEins=1, EZwei=2, ..' haben nichts verändert. Jemand eine Idee? |
AW: Array [Auszählungstyp] of irgendwas?
Zitat:
Delphi-Quellcode:
ein paar Probleme mitbringt, ist es doch besser, diese Probleme von Anfang an zu vermeiden, als mühsam zu versuchen diese Probleme wieder auszubügeln.
TEnum = ( Anfang = 1, Mitte = 3, Ende = 5);
Und dein Problem mit dem Enum kann ich so nicht nachvollziehen (funktioniert wie erwartet)
Delphi-Quellcode:
liefert
program dp_178091;
{$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils, System.TypInfo; type TEreignis = ( EEins, EZwei, EDrei, EVier, EFuenf, ESechs, ESieben, EAcht, ENeun ); const g_EreignisTypName : array [TEreignis] of string = ( 'the', 'quick', 'brown', 'fox', 'jumps', 'over', 'the', 'lazy', 'dog' ); procedure Test; var LEreignis : TEreignis; begin for LEreignis := low( TEreignis ) to high( TEreignis ) do Writeln( Ord( LEreignis ), ' (', GetEnumName(TypeInfo(TEreignis),Integer(LEreignis)), ') - ', g_EreignisTypName[LEreignis] ); end; begin try Test; except on E : Exception do Writeln( E.ClassName, ': ', E.Message ); end; ReadLn; end.
Code:
0 (EEins) - the
1 (EZwei) - quick 2 (EDrei) - brown 3 (EVier) - fox 4 (EFuenf) - jumps 5 (ESechs) - over 6 (ESieben) - the 7 (EAcht) - lazy 8 (ENeun) - dog |
AW: Array [Auszählungstyp] of irgendwas?
Zitat:
|
AW: Array [Auszählungstyp] of irgendwas?
Zitat:
Delphi-Quellcode:
deklariert wird und dann
TEreignis
Delphi-Quellcode:
... ok, die strings in der array definition sind so auch nicht syntaktisch korrekt ...
array[TEreignisTyp]
Ich liebe diese "... so ähnlich, ungefähr, nun ja, ist es es und das tut nicht ..." |
AW: Array [Auszählungstyp] of irgendwas?
Zitat:
|
AW: Array [Auszählungstyp] of irgendwas?
Zitat:
Delphi-Quellcode:
entspricht
Exit(Result);
Delphi-Quellcode:
begin
if a < b then Exit(a) else Exit(b); Exit(0); end;
Delphi-Quellcode:
Ob hier Delphi meint, daß
begin
if a < b then begin Result := a; Exit; end else begin Result := b; Exit; end; Result := 0; end;
Delphi-Quellcode:
nicht verwendet wird, weiß ich nicht, aber eventuell ja z.B. nach einem
Exit(0);
Delphi-Quellcode:
das auch bemängelt wird.
Raise
Bei dem
Delphi-Quellcode:
wird jedenfalls (glaub ich) gewarnt, daß es nicht verwendet wird.
Result := 0;
Beim Nächsten wird dagegen definitiv bemängelt, daß
Delphi-Quellcode:
und
Result := a
Delphi-Quellcode:
nicht verwendet werden.
Result := b
Delphi-Quellcode:
Es gibt eigentlich schon recht viele Warnungen, welcher der Compiler wirft, vorallem an vielen Stellen, wo Variablen zugewiesen, aber deren Wert nicht verwendet wird, da später ein anderer Wert zugewiesen, aber zwischendurch Dieser nicht mehr ausgelesen/verwendet wird.
begin
if a < b then Result := a else Result := b; Result := 0; end; Genauso wie an fast allen Stellen die "nicht initialisiert" Warnung kommt. (abgesehn von ein paar kleinen gemeinen, aber seltenen Fällen, mit Strings und Interfaces) |
AW: Array [Auszählungstyp] of irgendwas?
Es tut mir leid, dass ich doch keine spannende Geschichte gefunden habe :oops:
Der Fehler Ereignis/EreignisTyp lag natürlich am aus-dem-Gedächtnis-hinschreiben. Zunächst mal habe ich gestern nicht richtig hingeschaut, das Array hatte auch im Tooltip die falsche Reihenfolge. Dann hatte ich vorher tatsächlich in der Definition die Einträge 6/7 und 8/9 im Array g_EreignisTypName vertauscht gehabt, aber danach korrigiert. Allerdings hatte ich in der Version den Export der Text-Lokalisierung (dafür sind die Nummern erforderlich) laufen lassen. Damit stand 'dog' unter 13 und 'lazy' unter 14. In der Folge hat er natürlich bei jedem Test die falsche Belegung wieder eingelesen und damit den eigentlich korrigierten Fehler wiederhergestellt. :wall: Nach erneutem Export bringt er die richtigen Texte heraus. Vielen Dank nochmal. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 00:26 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz