![]() |
TOLEEnum Umwandlung aus String
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; |
AW: TOLEEnum Umwandlung aus String
Du verwendest einmal
Delphi-Quellcode:
, deklariert ist aber
TEnumUtils.GetEnumToString<T>
Delphi-Quellcode:
.
TEnumUtils.GetEnumFromString<T>
Allerdings wird der eigentliche Grund der sein, dass
Delphi-Quellcode:
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.
type
CountryCode2 = TOleEnum; |
AW: TOLEEnum Umwandlung aus String
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:
Nachdem was ich bisher gelesen habe, ist damit aber nicht mehr möglich mit RTTI zu arbeiten.
// Konstanten für enum CountryCode2
type CountryCode2 = TOleEnum; const CountryCode2_unk = $00000000; CountryCode2_AL = $0000414C; CountryCode2_AD = $00004144; ... Gruß Michael |
AW: TOLEEnum Umwandlung aus String
Eine syntaktisch funktionierende Lösung wäre eine Deklaration in etwa so:
Delphi-Quellcode:
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).
type
{$SCOPEDENUMS ON} TCountryCode = (unk, AL, AD, AT, BA, BG, ...); 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:
Die Verwendung ist dann schon deutlich aufgeräumter, aber dafür muss man schon einen gewissen Aufwand treiben.
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; |
AW: TOLEEnum Umwandlung aus String
Zitat:
ich nutze sowas in der Art, aber verzichte auf die Properties.
Delphi-Quellcode:
Welchen Vorteil hätte ich, wenn ich an dieser Stelle Properties benutze?
type
TCountryCodeHelper = record helper for TCountryCode function AsOleEnum : Cardinal; function AsString : String; end; 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; |
AW: TOLEEnum Umwandlung aus String
Zitat:
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. |
AW: TOLEEnum Umwandlung aus String
Zitat:
Ist aber richtig, das macht man nur einmal und dann ist es für immer drin :thumb: 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. |
AW: TOLEEnum Umwandlung aus String
Hallo Uwe,
ich habe den Record Helper verwendet und es funktioniert sehr gut. Vielen Dank für den Beispielcode. Auch an alle Anderen vielen Dank für eure Hilfe. VG Michael :-D |
AW: TOLEEnum Umwandlung aus String
Hallo Uwe,
ich habe deinen Code ausprobiert und bin dabei auf folgendes Problem bei der Rückwandlung des TOLEEnum in einen String gestoßen. Bei der Verwendung der Funktion GetasString wird die als TCountryCode gecastete Variable von CountryCode2 übergeben (CountryCode2_DE = 17477). Zitat:
Als Alternative hatte ich mir folgenden Code überlegt (ich habe die Variablen cOLEEnums umbenannt)
Delphi-Quellcode:
Da Cardinal(Self) mit dem Wert 69 in der Funktion ankommt, ist eine Iteration mit Vergleich über cCountryEnums nicht möglich. Wie kann ich den ursprünglich übergebenen Wert 17477 der Funktion erhalten? Vielen Dank.
function TCountryCodeHelper.GetCountryAsString: string;
begin Result := 'CountryCode_unk'; for var idx := Low(cCountryEnums) to High(cCountryEnums) do begin if cCountryEnums[idx] = Cardinal(Self) then begin Result := TRttiEnumerationType.GetName<TCountryCode>(idx); break; end; end; end; VG Michael |
AW: TOLEEnum Umwandlung aus String
Zitat:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 16:11 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