AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

TOLEEnum Umwandlung aus String

Ein Thema von Humbucker · begonnen am 4. Nov 2024 · letzter Beitrag vom 5. Nov 2024
Antwort Antwort
Humbucker

Registriert seit: 8. Feb 2013
Ort: im Lahntal
30 Beiträge
 
Delphi 10.4 Sydney
 
#1

TOLEEnum Umwandlung aus String

  Alt 4. Nov 2024, 14:29
Hallo Forum,
ich benötige eine Funktion zur Umwandlung eines String in einen Enumerator. Bei der Umwandlung stoße ich auf das Problem, dass der Typ des TOLEnum als tkInteger identifiziert wird. Daher versucht die Systemroutine GetEnumValue den eingehenden String als Integer zu casten, was natürlich schief geht. Über RTTI komme ich erst gar nicht zur der Systemroutine GetEnumValue. Was kann ich tun? Danke für eure Hilfe.

Code:
country := Map.GetCountryCode<CountryCode2>('DE'); //erwartetes Ergebnis: Enumerator CountryCode2_DE aus Unit PDF_Xpansion_Wrapper_16_TLB;

class function Map.GetCountryCode<T>(aLKZ: String) : T;
var
   lLKZ : string;
begin
   ......
   lLKZ := 'CountryCode2_' + copy(lLKZ,1,2); //nur die ersten beiden Stellen übertragen = USA -> US
   Result := TEnumUtils.GetEnumFromString<T>(lLKZ);
end;

class function TEnumUtils.GetEnumFromString<T>(aEnumString: String) : T;
    var
      lValue   : T;
  begin
    lValue := TRttiEnumerationType.GetValue<T>(aEnumString); --> Fehlermeldung: Ungültige Typumwandlung (TOLEEnum = tkInteger <> tkEnumeration)
    Result := T(lValue);
end;


unit System.Rtti;

class function TRttiEnumerationType.GetValue<T{: enum}>(const AName: string): T;
var
  v: Integer;
begin
  case PTypeInfo(TypeInfo(T))^.Kind of
    tkEnumeration:
      case System.TypInfo.GetTypeData(TypeInfo(T))^.OrdType of
        otUByte, otSByte: PByte(@Result)^ := GetEnumValue(TypeInfo(T), AName);
        otUWord, otSWord: PWord(@Result)^ := GetEnumValue(TypeInfo(T), AName);
        otULong, otSLong: PInteger(@Result)^ := GetEnumValue(TypeInfo(T), AName);
      end;
  else
    raise EInvalidCast.CreateRes(@SInvalidCast);
  end;
end;


unit PDF_Xpansion_Wrapper_16_TLB;

// Konstanten für enum CountryCode2
type
  CountryCode2 = TOleEnum;
const
  CountryCode2_unk = $00000000;
  CountryCode2_AL = $0000414C;
  CountryCode2_AD = $00004144;
  CountryCode2_AT = $00004154;
  CountryCode2_BA = $00004241;
  CountryCode2_BG = $00004247;
  CountryCode2_CA = $00004341;
  CountryCode2_CN = $0000434E;
  CountryCode2_HR = $00004852;
  CountryCode2_CZ = $0000435A;
  CountryCode2_CY = $00004359;
  CountryCode2_DK = $0000444B;
  CountryCode2_EE = $00004545;
  CountryCode2_FI = $00004649;
  CountryCode2_FR = $00004652;
  CountryCode2_DE = $00004445;
 ....


unit WinAPI.ActiveX

TOleEnum = type LongWord;
Michael H.

Geändert von Humbucker ( 5. Nov 2024 um 10:41 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.430 Beiträge
 
Delphi 12 Athens
 
#2

AW: TOLEEnum Umwandlung aus String

  Alt 4. Nov 2024, 14:54
Du verwendest einmal TEnumUtils.GetEnumToString<T> , deklariert ist aber TEnumUtils.GetEnumFromString<T> .

Allerdings wird der eigentliche Grund der sein, dass
Delphi-Quellcode:
type
  CountryCode2 = TOleEnum;
keine Enumeration im Sinne von Delphi darstellt, bei der die einzelnen Werte als Strings dargestellt werden. Intern ist das ein normaler Integer gedanklich kombiniert mit einer Liste von Integer-Konstanten, aber eben kein Typ mit dem TRttiEnumerationType etwas anfangen kann.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Humbucker

Registriert seit: 8. Feb 2013
Ort: im Lahntal
30 Beiträge
 
Delphi 10.4 Sydney
 
#3

AW: TOLEEnum Umwandlung aus String

  Alt 5. Nov 2024, 11:02
Hallo Uwe,
danke für deine Nachricht. Ich habe die Funktion umbenannt, aber das ist in der Tat nicht das Problem.
Es ist genau wie du sagst, die Enumeratoren werden von Delphi nicht als solche erkannt.
Gibt es dann überhaupt eine Möglichkeit über den Bezeichner den Wert zu erhalten?
Vielleicht ist es eine sinnvolle Vorgehensweise die (benötigten) Enumeratoren neu zu definieren und dann als TOLEEnum zu casten?

Code:
// Konstanten für enum CountryCode2
type
  CountryCode2 = TOleEnum;
const
  CountryCode2_unk = $00000000;
  CountryCode2_AL = $0000414C;
  CountryCode2_AD = $00004144;
  ...
Nachdem was ich bisher gelesen habe, ist damit aber nicht mehr möglich mit RTTI zu arbeiten.

Gruß Michael
Michael H.
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.430 Beiträge
 
Delphi 12 Athens
 
#4

AW: TOLEEnum Umwandlung aus String

  Alt 5. Nov 2024, 11:57
Eine syntaktisch funktionierende Lösung wäre eine Deklaration in etwa so:
Delphi-Quellcode:
type
{$SCOPEDENUMS ON}
  TCountryCode = (unk, AL, AD, AT, BA, BG, ...);
Damit würde TRttiEnumerationType.GetValue<TCountryCode>(AStrin g) einen AString wie z.B. "AL" oder "BG" in den entsprechenden TCountryCode umwandeln, also TCountryCode.AL bzw. TCountryCode.BG (Das "CountryCode2_" Prefix kann man sich dann sparen).

Allerdings muss man dann noch die Umsetzung in die entsprechenden TOleEnum-Werte realisieren. Dazu bietet sich eine record helper an, in dem man auch gleich die String-Umwandlung unterbringen kann:
Delphi-Quellcode:
type
  TCountryCodeHelper = record helper for TCountryCode
  private const
    cOleEnums: array[TCountryCode] of Cardinal = (
      CountryCode2_unk,
      CountryCode2_AL,
      CountryCode2_AD,
      ...
      );
    function GetAsOleEnum: Cardinal;
    function GetAsString: string;
    procedure SetAsOleEnum(const Value: Cardinal);
    procedure SetAsString(const Value: string);
  public
    property AsOleEnum: Cardinal read GetAsOleEnum write SetAsOleEnum;
    property AsString: string read GetAsString write SetAsString;
  end;

function TCountryCodeHelper.GetAsOleEnum: Cardinal;
begin
  Result := cOleEnums[Self];
end;

function TCountryCodeHelper.GetAsString: string;
begin
  Result := TRttiEnumerationType.GetName<TCountryCode>(Self);
end;

procedure TCountryCodeHelper.SetAsOleEnum(const Value: Cardinal);
begin
  for var idx := Low(cOleEnums) to High(cOleEnums) do begin
    if cOleEnums[idx] = Value then begin
      Self := idx;
      Exit;
    end;
  end;
  Self := TCountryCode.unk;
end;

procedure TCountryCodeHelper.SetAsString(const Value: string);
begin
  try
    Self := TRttiEnumerationType.GetValue<TCountryCode>(Value);
    if Ord(Self) < Ord(Low(TCountryCode)) then
      raise EInvalidCast.CreateRes(@SInvalidCast);
  except
    on EInvalidCast do
      Self := TCountryCode.unk;
  end;
end;
Die Verwendung ist dann schon deutlich aufgeräumter, aber dafür muss man schon einen gewissen Aufwand treiben.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Rollo62

Registriert seit: 15. Mär 2007
4.065 Beiträge
 
Delphi 12 Athens
 
#5

AW: TOLEEnum Umwandlung aus String

  Alt 5. Nov 2024, 15:17
Delphi-Quellcode:
type
  TCountryCodeHelper = record helper for TCountryCode
  private const
    cOleEnums: array[TCountryCode] of Cardinal = (
      CountryCode2_unk,
      CountryCode2_AL,
      CountryCode2_AD,
      ...
      );
    function GetAsOleEnum: Cardinal;
    function GetAsString: string;
    procedure SetAsOleEnum(const Value: Cardinal);
    procedure SetAsString(const Value: string);
  public
    property AsOleEnum: Cardinal read GetAsOleEnum write SetAsOleEnum;
    property AsString: string read GetAsString write SetAsString;
  end;
Hallo Uwe,

ich nutze sowas in der Art, aber verzichte auf die Properties.

Delphi-Quellcode:
type
  TCountryCodeHelper = record helper for TCountryCode
    function AsOleEnum : Cardinal;
    function AsString : String;
  end;
Welchen Vorteil hätte ich, wenn ich an dieser Stelle Properties benutze?
Ich meine Funktionen machen das genauso, oder übersehe ich da etwas?


Sorry, es ging Dir ja um Setter und Getter, dann ist es klar.

Ich mache das mehr so, weil es nicht immer passende Konvertierungen gibt.
Delphi-Quellcode:
type
  TCountryCodeHelper = record helper for TCountryCode
    function ToOleEnum : Cardinal;
    function TryFromOleEnum( AVal : Cardinal ) : Boolean;

    function ToString : String;
    function TryFromString( AVal : String ) : Boolean;
  end;

Geändert von Rollo62 ( 5. Nov 2024 um 15:21 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.430 Beiträge
 
Delphi 12 Athens
 
#6

AW: TOLEEnum Umwandlung aus String

  Alt 5. Nov 2024, 15:37
Ich mache das mehr so, weil es nicht immer passende Konvertierungen gibt.
Bei den Settern ist das durchaus sinnvoll. Da es hier aber ein dediziertes Unknown gibt, kann man halt das als Fallback verwenden. Kommt immer auf die Verwendung an.

Die Getter müssen indes immer liefern können. Alles andere wäre ein Programmierfehler (zumindest bei dieser Art Anwendungsfälle). Bei der String-Rückgabe von unk könnte man über einen Leerstring diskutieren, aber das passt dann nicht mehr ganz zum RTTI-Ansatz.

OT: Ich bin eigentlich ein Freund von Properties. Die Anweisungen lassen sich dann einfacher mit dem Reverse Assignment Feature oder dem try-finally-Wizard umdrehen.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Rollo62

Registriert seit: 15. Mär 2007
4.065 Beiträge
 
Delphi 12 Athens
 
#7

AW: TOLEEnum Umwandlung aus String

  Alt 5. Nov 2024, 18:31
OT: Ich bin eigentlich ein Freund von Properties.
Ja ich schon auch, aber der Mehraufwand ist halt auch da.
Ist aber richtig, das macht man nur einmal und dann ist es für immer drin

Bei nicht vorhandenem Unknown wäre bei einem Getter ja nur noch eine Exception möglich,
was ich persönlich für den einfachen Enum ( <> Integer ) etwas zu hart finde.
Deshalb bevorzuge ich TryFromXyz, da kann ich dann explizit drauf reagieren.

Ich nutze das oft um enum => Integer oder enum => String und zurück umzuwandeln, z.B. für Serialisierung oder Persistance.
Dabei sollte es meiner Meinung nach besser einen 1:1 Match geben, auch bei Unknown, und keinen Fallback, was zu Misinterpretation führen könnte.

Nur wenn es eben nicht exakt in das Enum reinpasst, dann gäbe es den Abbruch bei TryFromXyz.
Das kann z.B. durch Versionsupdates oder ähnliches leicht passieren.
  Mit Zitat antworten Zitat
Antwort Antwort

 

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 04:01 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