AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Object-Pascal / Delphi-Language Delphi Prüfen ob Integer im Enumeration-Type enthalten ist
Thema durchsuchen
Ansicht
Themen-Optionen

Prüfen ob Integer im Enumeration-Type enthalten ist

Ein Thema von Keks · begonnen am 25. Jan 2015 · letzter Beitrag vom 27. Jan 2015
Antwort Antwort
Seite 1 von 3  1 23      
Keks

Registriert seit: 25. Mai 2005
122 Beiträge
 
#1

Prüfen ob Integer im Enumeration-Type enthalten ist

  Alt 25. Jan 2015, 15:41
Delphi-Version: XE
Angenommen ich habe folgendes:
type TMeinBeispiel = (mbEins=0, mbZwei=1, mbDrei=5);

Jetzt erhalte ich einen Integer i aus einer externen Quelle (Ini, DB, etc.) und möchte diesen zu TMeinBeispiel casten.
Per MeinBeispiel := TMeinBeispiel(i); funktioniert dies immer. Auch dann, wenn i gar nicht in TMeinBeispiel vorhanden ist. Dann hat MeinBeispiel schlicht den Wert i angenommen (der Debugger sagt "out of bound (i)").

Nun würde ich gerne bei Werten, die nicht in der Aufzählung vorhanden sind, einen Standardwert vorgeben.
Wie kann ich nun aber prüfen, ob ein Wert enthalten ist (0, 1, 5: True; 3, 6: False)? Sowas wie if i in TMeinBeispiel then funktioniert ja leider nicht.

Muss ich den unschönen Umweg über GetEnumName/GetEnumValue gehen oder gibt es eine elegantere Lösung?
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.034 Beiträge
 
Delphi 12 Athens
 
#2

AW: Prüfen ob Integer im Enumeration-Type enthalten ist

  Alt 25. Jan 2015, 16:24
Für Emums man man maximal in der RTTI abfragen was der größte Wert ist, aber nur, wenn das ein Enum ohne Wertdefinitionen ist, denn dann gibt es in der RTTI keine Namensliste.

Also gerade dein Beispiel ist so nicht und niemals lösbar.
Zitat:
type TMeinBeispiel = (mbEins=0, mbZwei=1, mbDrei=5);
Nur ohne "=", also bei type TMeinBeispiel = (mbEins, mbZwei, mbDrei); existiere vollständige RTTI-Infos.

Ansonsten kann man nur den maximalen Wertebereich prüfen und nichts die einzelnen "Werte".
für Enums: 0..255, 0..65535 oder 0..4294967295
für Sets: 0..7, 0..15, 0..31, 0..63, ... bis maximal 0..255



Der Compiler rundet alles auf den nächst größeren kleinstmöglichen Speichertypen, also bei deinem TMeinBeispiel (als Enum) ist das genau ein Byte und somit passt in den Typen grundsätzlich erstmal alles rein, von 0 bis 255 und als Set 0 bis 7.

Zitat:
Muss ich den unschönen Umweg über GetEnumName/GetEnumValue gehen oder gibt es eine elegantere Lösung?
Das hast du vermutlich noch nicht probiert, denn bei deinem TMeinBeispiel ergibt das eine geile Exception. (und mein Lösungsvorschlag, für das Problem, wurde vor vielen Jahren schon ignoriert)
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests

Geändert von himitsu (25. Jan 2015 um 16:36 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#3

AW: Prüfen ob Integer im Enumeration-Type enthalten ist

  Alt 25. Jan 2015, 16:56
Gerade wenn die Bedeutung zwischen internem und externem System ausgetauscht werden muss, empfiehlt sich ein eigener DatenTyp um so auch typischer im Kontext zu bleiben.
Delphi-Quellcode:
unit Unit2;

interface

type
  TMeinBeispiel = record
  private const
    VALID_VALUES: array [0 .. 2] of Integer = ( 0, 1, 5 );
    class function GetValue( const Index: Integer ): TMeinBeispiel; static;
  public
    class function Values: TArray<TMeinBeispiel>; static;
    class property Eins: TMeinBeispiel index 0 read GetValue;
    class property Zwei: TMeinBeispiel index 1 read GetValue;
    class property Drei: TMeinBeispiel index 2 read GetValue;
  public
    class operator implicit( const a: Integer ): TMeinBeispiel;
    class operator implicit( const a: TMeinBeispiel ): Integer;

    class operator Equal( const a, b: TMeinBeispiel ): Boolean;
    class operator NotEqual( const a, b: TMeinBeispiel ): Boolean;
    // hier können noch weitere Operatoren definiert werden, je nach Belieben
  private
    FValue: Integer;
  public
    constructor Create( const Value: Integer );
    property Value: Integer read FValue;
  end;

implementation

uses
  System.SysUtils;

{ TMeinBeispiel }

constructor TMeinBeispiel.Create( const Value: Integer );
var
  LIdx: Integer;
begin
  for LIdx := Low( VALID_VALUES ) to High( VALID_VALUES ) do
    if Value = VALID_VALUES[LIdx]
    then
      begin
        FValue := Value;
        Exit;
      end;
  raise EConvertError.CreateFmt( '%d kein gültiger Wert für TMeinBeispiel', [Value] );
end;

class operator TMeinBeispiel.Equal( const a, b: TMeinBeispiel ): Boolean;
begin
  Result := a.FValue = b.FValue;
end;

class function TMeinBeispiel.GetValue( const Index: Integer ): TMeinBeispiel;
begin
  Result := TMeinBeispiel.VALID_VALUES[Index];
end;

class operator TMeinBeispiel.implicit( const a: Integer ): TMeinBeispiel;
begin
  Result := TMeinBeispiel.Create( a );
end;

class operator TMeinBeispiel.implicit( const a: TMeinBeispiel ): Integer;
begin
  Result := a.FValue;
end;

class operator TMeinBeispiel.NotEqual( const a, b: TMeinBeispiel ): Boolean;
begin
  Result := not( a = b );
end;

class function TMeinBeispiel.Values: TArray<TMeinBeispiel>;
var
  LIdx: Integer;
begin
  SetLength( Result, Length( TMeinBeispiel.VALID_VALUES ) );
  for LIdx := Low( TMeinBeispiel.VALID_VALUES ) to High( TMeinBeispiel.VALID_VALUES ) do
    begin
      Result[LIdx] := TMeinBeispiel.VALID_VALUES[LIdx];
    end;
end;

end.
Und man benutzt das dann einfach
Delphi-Quellcode:
procedure DoWithValue( AValue : TMeinBeispiel );
begin
  // irgendwas damit machen
end;

begin
  DoWithValue( 5 ); // <- Wert aus der Datenbank ist ein einfacher Integer
end.
Unzulässige Typen werden mit einer Exception direkt beim Umwandeln quittiert.
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)
  Mit Zitat antworten Zitat
Keks

Registriert seit: 25. Mai 2005
122 Beiträge
 
#4

AW: Prüfen ob Integer im Enumeration-Type enthalten ist

  Alt 25. Jan 2015, 17:28
Huiuiui, da werden aber große Geschütze aufgefahren!

Ich dachte, mein Lösungsansatz (GetEnumName/GetEnumValue) sei zu umständlich und es müsse doch irgendwie einfacher gehen.
Aber bei Sir Rufos Lösung (Vielen Dank für die Mühe!) bin ich doch etwas baff.

Ich habe jetzt mal meinen Ansatz ausprobiert:
Delphi-Quellcode:
var
  MeinBeispiel: TMeinBeispiel;
begin
  MeinBeispiel := GetEnumMeinBeispielDefault(i);

...

function GetEnumMeinBeispielDefault(const value: Integer): TMeinBeispiel;
var
  s: String;
  i: Integer;
begin
  s := GetEnumName(TypeInfo(TMeinBeispiel), value);
  i := GetEnumValue(TypeInfo(TMeinBeispiel), s); //s enthält "Speichermüll", wenn value nicht in TMeinBeispiel, statt leer zu sein
  if i>0 then
    Result := TTrayAction(value)
  else
    Result := mbEins; //Default-Wert
end;
Aber das geht wohl nur, wenn TMeinBeispiel keine manuelle Indizes-Anpassung erhält, sonst "Type 'TMeinBeispiel' has no type info". Das ist wohl das, was himitsu meinte.

Wie gesagt war meine ursprüngliche Hoffnung, dass es sowas wie if i in TMeinBeispiel then geben müsste, deren Syntax mir nicht bekannt ist. Letztlich sind in der Aufwählung einige Werte manuell festgelegt (0,1,5) und ich möchte gegen diese einen anderen Wert vergleichen.

Geändert von Keks (25. Jan 2015 um 17:32 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#5

AW: Prüfen ob Integer im Enumeration-Type enthalten ist

  Alt 25. Jan 2015, 17:53
Ich stelle mir immer die Frage nach Typsicherheit und der Bequemlichkeit nach der "Anstrengung". Du kannst dir auch einen Record erstellen der zwischen dem ENUM und dem korrespondierendem Integer-Wert vermittelt. Alle Schnittstellen benutzen den Record, die Anwendung den ENUM und die Datenbank den Integer. Das geht auch.
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.034 Beiträge
 
Delphi 12 Athens
 
#6

AW: Prüfen ob Integer im Enumeration-Type enthalten ist

  Alt 25. Jan 2015, 17:58
Wie gesagt, ohne Typ-Info bleibt nur noch die Speichergröße.
Und die Typinfo fehlt, weil man zu blöd ist und es nicht schafft "fehlende" Werte in die Namensliste aufzunehmen.

Du kannst dir auch einen Record erstellen der zwischen dem ENUM und dem korrespondierendem Integer-Wert vermittelt.
Zitat:
Delphi-Quellcode:
class operator implicit( const a: Integer ): TMeinBeispiel;
class operator implicit( const a: TMeinBeispiel ): Integer;
Jupp, statt nur zwischem dem Record und Integer zu casten, kann man auch noch den Enum mit in die Casts aufnemen und zusätzlich vielleicht noch Getter-, Setter- und Übersetzngsmethoden implementieren.
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests

Geändert von himitsu (25. Jan 2015 um 18:17 Uhr)
  Mit Zitat antworten Zitat
Keks

Registriert seit: 25. Mai 2005
122 Beiträge
 
#7

AW: Prüfen ob Integer im Enumeration-Type enthalten ist

  Alt 25. Jan 2015, 18:17
Beim Debuggen sehe ich:
Delphi-Quellcode:
mb := TMeinBeispiel(1); //mb = mbZwei
mb := TMeinBeispiel(4); //mb = (out of bound) 4
Der Debugger stellt hierbei doch auch irgendwie fest, ob der Wert unter den vorgegebenen Werten ist oder nicht. Man selbst kann das aber nicht tun?
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.034 Beiträge
 
Delphi 12 Athens
 
#8

AW: Prüfen ob Integer im Enumeration-Type enthalten ist

  Alt 25. Jan 2015, 18:26
k.A. wo der Debugger die Werte her holt, aber in der einkompilierten RTTI fehlt ganz einfach die Liste der Namen, sobald man selber die Werte zuweist.
Und die neue erweiterte RTTI geht bei Enums IMHO auch nur auf die alte RTTI.

Es wird dafür ein Array verwendt, wie man es z.B. von der Registry und anderen WinAPIs kennt.
'NameFürWert0'#0'NameFürWert1'#0'NameFürWert2'#0'NameFürWert3'#0#0
Und wenn man jetzt Werte weg lässt, dann entstünde #0#0, was ja dem Listenende entspricht, und die Liste wäre unvollständig/kaputt. Darum lässt der doofe Compiler/Linker diese Liste einfach ganz weg, anstatt z.B. einen "Dummy"-Wert einzufügen oder eine andere Speicherstruktur zu benutzen.
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests

Geändert von himitsu (25. Jan 2015 um 18:30 Uhr)
  Mit Zitat antworten Zitat
Keks

Registriert seit: 25. Mai 2005
122 Beiträge
 
#9

AW: Prüfen ob Integer im Enumeration-Type enthalten ist

  Alt 25. Jan 2015, 18:46
k.A. wo der Debugger die Werte her holt, aber in der einkompilierten RTTI fehlt ganz einfach die Liste der Namen, sobald man selber die Werte zuweist.
Moment, aber ich brauche doch gar nicht die Namen, sondern nur die Zahlen-Werte!?
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.034 Beiträge
 
Delphi 12 Athens
 
#10

AW: Prüfen ob Integer im Enumeration-Type enthalten ist

  Alt 25. Jan 2015, 18:58
Es werden aber nicht die Zahlen gespeichert, sondern die Namen, in einem indizierten Array. (Index = Zahl )

Als Zahl ist alles im Wertebereich des Speichertyps gültig.
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests

Geändert von himitsu (25. Jan 2015 um 19:00 Uhr)
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 3  1 23      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 11:51 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