Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Generisches ToString für Enumerations (https://www.delphipraxis.net/160167-generisches-tostring-fuer-enumerations.html)

s.h.a.r.k 30. Apr 2011 14:25

Delphi-Version: XE

Generisches ToString für Enumerations
 
Hallo zusammen,

habe gerade mal wieder ein Problem bzgl. meiner Log-Klasse. Ich hätte gerne folgendes:
Delphi-Quellcode:
type
  TTestEnum = (teOne, teTwo, teThree {...});
  TTestEnumSet = set of TTestEnum;

var
  a : TTestEnum;
  b : TTestEnumSet;
begin
  a := teOne;
  TLog.Add(a); // -> liefert dann den String "teOne"

  // DAS HIER MAL NICHT BEACHTEN!!!
  //b := [teTwo, teThree];
  //TLog.Add(b); // -> Liefert den String "[teTwo, teThree]"
end;
Das Problem hierbei ist ja, dass die Add-Methode keine Ahnung von TTestEnum hat, d.h. ich sollte diese generisch gestalten, was an sich ja kein Problem wäre. Jetzt kommt allerdings das ABER: bei Generics gibts ja keine Einschränkung, dass ich eben nur Enumeration-Typen übergeben kann und somit funktioniert folgendes ja nicht:
Delphi-Quellcode:
uses
  TypInfo;

procedure TLog.Add<T>(Value: T);
var
  s : string;
begin
  s := GetEnumName(TypeInfo(T), Integer(Value)); // <- [DCC Fehler] Project1.dpr(27): E2089 Ungültige Typumwandlung
  { ... }
end;
Habt ihr eine Idee, wie man das Dilemma umgehen kann?

rollstuhlfahrer 30. Apr 2011 14:37

AW: Generisches ToString für Enumerations
 
muss da nicht ein
Delphi-Quellcode:
Ord(Value)
hin?? (vgl. OH)

Bernhard

himitsu 30. Apr 2011 14:43

AW: Generisches ToString für Enumerations
 
Jupp, entweder Delphi-Referenz durchsuchenOrd oder ein Integer-Typ, welcher die gleiche Größe hat. :wink:

SizeOf(Integer) <> SizeOf(TTestEnumSet)

Versuch mal Byte, Word, LongWord/LongInt oder UInt64/Int64.

s.h.a.r.k 30. Apr 2011 14:50

AW: Generisches ToString für Enumerations
 
Selbst mit Ord() scheitert das ganze:
Delphi-Quellcode:
[DCC Fehler] Project1.dpr(30): E2008 Inkompatible Typen
PS: Beachtet das mit dem set mal noch nicht.

rollstuhlfahrer 30. Apr 2011 15:05

AW: Generisches ToString für Enumerations
 
Jetzt bleibt noch die Frage, wo Delphi gerade den Fehler meldet (beim 1. oder 2. Parameter)?

Bernhard

daywalker9 30. Apr 2011 15:32

AW: Generisches ToString für Enumerations
 
Ich habs so gelöst:

Delphi-Quellcode:
class function TEnumGen<T>.GetName(AVal: T): string;
var
  bVal : Byte;
begin
  move(AVal,bVal,SizeOf(T));
  Result:=GetEnumName(TypeInfo(T),bVal);
end;

s.h.a.r.k 30. Apr 2011 15:34

AW: Generisches ToString für Enumerations
 
Ha, ich habs :stupid:

Delphi-Quellcode:
TLog = record
  class procedure AddEnum<T>(V: T); static;
end;

class procedure TLog.AddEnum<T>(V: T);
begin
  Writeln(GetEnumName(TypeInfo(T), PByte(@V)^));
end;
Der Tipp von himitsu war gut. Jetzt muss ich nur noch testen, ob das auch immer passen sollte. In meinen Fall passts jedenfalls. Aber man kann ja auch gewisse Werte für die Enum-Elemente definieren. Melde mich gleich wieder.

@daywalker: klar, so gehts auch :)

-- EDIT: So, habe mich jetzt nochmals ein wenig mit diesen Enumerations befasst und bin auf ein weiteres Problem gestoßen, welches dieses Zitat auf den Punkt bringt:
Zitat:

Zitat von http://delphi.wikia.com/wiki/GetEnumValue_Routine
Be aware that Typeinfo will be lost when the enumeration is given different ordinal values. With the next enumeration example it's not possible to use GetEnumValue and will result in 'E2134 Type 'TTestType' has no type info'

Schade, aber man kann daran wohl nix ändern.

Stevie 30. Apr 2011 16:14

AW: Generisches ToString für Enumerations
 
In der Logging Bibliothek, die wir in der Firma nutzen (recht bekanntes kommerzielles Produkt) ist das so gelöst, dass man bei LogEnum den Ordinalwert und den TypInfo übergibt. Da ist allerdings auch nix mit Generics.

s.h.a.r.k 30. Apr 2011 16:17

AW: Generisches ToString für Enumerations
 
Ich unterstütze alles ab Delphi 2010, da ich teilweise rege Verwendung der neuen RTTI mache. Nachdem es auch die netten Generics gibt, will ich dem Nutzer der Log-Komponente (Hauptnutzer bin wohl ich :mrgreen:) so viel wie möglich abnehmen. Daher mein Ansatz, aber danke für den Hinweis.

-- Edit: Hier noch schnell der Record mit den entsprechenden Methoden. Die Methode StrToEnum() gibt es in der TypInfo-Unit auch und heißt dort GetEnumValue(). Allerdings liefert GetEnumValue() einen Integer und müsste somit nochmals zusätzlich gecastet werden, was hier nicht der Fall ist -> Typsicherheit!
Delphi-Quellcode:
TEnumHelper = record
  class function EnumToStr<T>(Value: T): String; static;
  class function StrToEnum<T>(Value: String): T; static;
end;

class function TEnumHelper.EnumToStr<T>(Value: T): String;
var
  ti : PTypeInfo;
begin
  ti := TypeInfo(T);
  if (ti = nil) then
    raise Exception.Create('Type has not type information.');
  if (ti.Kind <> tkEnumeration) then
    raise Exception.Create('Type is not an enumeration.');
  Result := GetEnumName(ti, PByte(@Value)^);
end;

class function TEnumHelper.StrToEnum<T>(Value: String): T;
var
  ti : PTypeInfo;
  i : Byte;
  pt : ^T;
begin
  ti := TypeInfo(T);
  if (ti = nil) then
    raise Exception.Create('Type has not type information.');
  if (ti.Kind <> tkEnumeration) then
    raise Exception.Create('Type is not an enumeration.');

  i := GetEnumValue(ti, Value);
  pt := @i;
  Result := pt^;
end;
Wenn noch wer was dran auszusetzen hat, dann nur her damit ;)

Stevie 30. Apr 2011 16:50

AW: Generisches ToString für Enumerations
 
Du solltest die Größe deines Enum Typens überprüfen, der muss nämlich nicht immer 1 Byte sein.


Alle Zeitangaben in WEZ +1. Es ist jetzt 05:08 Uhr.
Seite 1 von 2  1 2      

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