Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Array [Auszählungstyp] of irgendwas? (https://www.delphipraxis.net/178091-array-%5Bauszaehlungstyp%5D-irgendwas.html)

Mikkey 17. Dez 2013 09:40

Delphi-Version: 7

Array [Auszählungstyp] of irgendwas?
 
Ich habe eine Typdefinition:

Delphi-Quellcode:
TEnum = (Anfang = 1, Mitte = 3, Ende = 5);
und ein String-Array, in denen die Werte des Typs beschrieben werden:

Delphi-Quellcode:
g_TEnumNames = Array[TEnum] of String =
  ('Anfang',
   '',
   'Mitte',
   '',
   'Ende');
Wenn ich die Leerstring-Einträge weglasse, mault der Compiler (Anzahlen stimmen nicht überein). Warum?

Noch extremer wird es (finde ich jedenfalls), wenn ich über den Typ iteriere:

Delphi-Quellcode:
pos: TEnum;
...
for pos := Low(TEnum) to High(TEnum) do
  TuIrgendwasMit(pos, g_TenumNames[pos]);
Die Schleife wird fünfmal durchlaufen, obwohl der Typ nur mit drei Werten definiert ist.

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)?

Furtbichler 17. Dez 2013 09:50

AW: Array [Auszählungstyp] of irgendwas?
 
Die einzige Möglichkeit, die mir einfällt, wäre:
Delphi-Quellcode:
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;
Anders würde der Compiler eine Sukkzessor-Funktion auf TEnum auch nicht umsetzen.

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');

himitsu 17. Dez 2013 09:54

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.

Namenloser 17. Dez 2013 09:55

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.

himitsu 17. Dez 2013 09:56

AW: Array [Auszählungstyp] of irgendwas?
 
Delphi-Quellcode:
Type TEnum = (Anfang, Mitte, Ende);
läßt sich via Delphi-Referenz durchsuchenGetEnumName (Hier im Forum suchenGetEnumName) in einen String übersetzen, welcher zufälig genau deinem Array entspricht.

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)

Mikkey 17. Dez 2013 10:16

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"

himitsu 17. Dez 2013 10:16

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 -> http://www.delphipraxis.net/178082-v...lean-zahl.html

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;

Mikkey 17. Dez 2013 10:59

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:
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];
Nochmals vielen Dank

sx2008 17. Dez 2013 11:03

AW: Array [Auszählungstyp] of irgendwas?
 
Wenn du unbedingt den Enumwerten eine Zahl zuordnen musst dann geht das so:
Delphi-Quellcode:
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")
);
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.
Der Code dazu spare ich mir -> Hausaufgabe.
Man kann den Record auch um weitere Infos erweitern wie z.B. die Schwere des Fehlers.

Namenloser 17. Dez 2013 11:06

AW: Array [Auszählungstyp] of irgendwas?
 
Zitat:

Zitat von Mikkey (Beitrag 1240104)
@ Namenloser: Roter Kasten?

Wenn man in der DP einen Beitrag abschickt und währenddessen bereits ein neuer Beitrag gepostet wurde, bekommt man einen roten Kasten als Warnmeldung.

himitsu 17. Dez 2013 11:25

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:
const
  miImageMove = Succ(High(TIEMouseInteractVtItems));
  miImageZoom = Succ(miImageMove);
TIEMouseInteractVtItems ist ein Enum, welcher den Zustand der Input-Verarbeitung angibt
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

Uwe Raabe 17. Dez 2013 11:35

AW: Array [Auszählungstyp] of irgendwas?
 
Zitat:

Zitat von Mikkey (Beitrag 1240090)
Delphi-Quellcode:
TEnum = (Anfang = 1, Mitte = 3, Ende = 5);
...
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)?

Man muss sich halt darüber in Klaren sein, daß man mit dem Zuweisen von Integerkonstanten bei der Deklaration der Enum-Werte eine Ordnungszahl definiert und nicht etwa einen willkürlichen Wert vergibt. Wenn man bei diesen Ordnungszahlen Lücken lässt, dann wird der Enum-Typ implizit um diese Lücken erweitert. Demnach sind solche Zuweisungen durchaus gültig:

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.

Sir Rufo 17. Dez 2013 18:37

AW: Array [Auszählungstyp] of irgendwas?
 
Und warum nicht so?
Delphi-Quellcode:
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 );
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.
Delphi-Quellcode:
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.
und
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.

Mikkey 17. Dez 2013 20:25

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:
{
  if (a<b)
    return a;
  else
    return b;
  return 0;
}
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.


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:
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');
Greife ich nun im Code auf das Array mit den Werten des Typs zu, erhalte ich die falschen Einträge:
Delphi-Quellcode:
s1 := g_EreignisTypName[EAcht];
s2 := g_EreignisTypName[ENeun];
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.

Auch als Test zugewiesene Integer per 'EEins=1, EZwei=2, ..' haben nichts verändert.

Jemand eine Idee?

Sir Rufo 17. Dez 2013 20:50

AW: Array [Auszählungstyp] of irgendwas?
 
Zitat:

Zitat von Mikkey (Beitrag 1240143)
@Sir Rufo:
Dass solche Verpackungsmöglichkeiten bestehen, ist schon klar. Es ging mir hauptsächlich um die Verwendung von Arrays per Aufzählungstyp.

Da aber dieses
Delphi-Quellcode:
TEnum = ( Anfang = 1, Mitte = 3, Ende = 5);
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.

Und dein Problem mit dem Enum kann ich so nicht nachvollziehen (funktioniert wie erwartet)
Delphi-Quellcode:
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.
liefert
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

Uwe Raabe 17. Dez 2013 21:05

AW: Array [Auszählungstyp] of irgendwas?
 
Zitat:

Zitat von Mikkey (Beitrag 1240143)
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.

Zeig mal den ganzen Code - da stimmt irgendetwas nicht.

Sir Rufo 17. Dez 2013 21:16

AW: Array [Auszählungstyp] of irgendwas?
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1240146)
Zitat:

Zitat von Mikkey (Beitrag 1240143)
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.

Zeig mal den ganzen Code - da stimmt irgendetwas nicht.

Es macht mich schon stutzig, dass da einmal
Delphi-Quellcode:
TEreignis
deklariert wird und dann
Delphi-Quellcode:
array[TEreignisTyp]
... ok, die strings in der array definition sind so auch nicht syntaktisch korrekt ...

Ich liebe diese "... so ähnlich, ungefähr, nun ja, ist es es und das tut nicht ..."

jaenicke 17. Dez 2013 22:17

AW: Array [Auszählungstyp] of irgendwas?
 
Zitat:

Zitat von Mikkey (Beitrag 1240143)
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.

Hast du auch die Optimierung unter Compiler in den Projektoptionen deaktiviert, wenn du debuggen möchtest? ;-)

himitsu 18. Dez 2013 01:30

AW: Array [Auszählungstyp] of irgendwas?
 
Zitat:

Zitat von Mikkey (Beitrag 1240143)
Code:
{
  if (a<b)
    return a;
  else
    return b;
  return 0;
}

Im C springt der beim Return raus, was dem heutigen
Delphi-Quellcode:
Exit(Result);
entspricht
Delphi-Quellcode:
begin
  if a < b then
    Exit(a)
  else
    Exit(b);
  Exit(0);
end;
Delphi-Quellcode:
begin
  if a < b then begin
    Result := a;
    Exit;
  end else begin
    Result := b;
    Exit;
  end;
  Result := 0;
end;
Ob hier Delphi meint, daß
Delphi-Quellcode:
Exit(0);
nicht verwendet wird, weiß ich nicht, aber eventuell ja z.B. nach einem
Delphi-Quellcode:
Raise
das auch bemängelt wird.
Bei dem
Delphi-Quellcode:
Result := 0;
wird jedenfalls (glaub ich) gewarnt, daß es nicht verwendet wird.

Beim Nächsten wird dagegen definitiv bemängelt, daß
Delphi-Quellcode:
Result := a
und
Delphi-Quellcode:
Result := b
nicht verwendet werden.
Delphi-Quellcode:
begin
  if a < b then
    Result := a
  else
    Result := b;
  Result := 0;
end;
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.
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)

Mikkey 18. Dez 2013 07:12

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 02:07 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz