AGB  ·  Datenschutz  ·  Impressum  







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

Generisches ToString für Enumerations

Ein Thema von s.h.a.r.k · begonnen am 30. Apr 2011 · letzter Beitrag vom 3. Mai 2011
Antwort Antwort
Seite 1 von 2  1 2      
Benutzerbild von Stevie
Stevie

Registriert seit: 12. Aug 2003
Ort: Soest
4.051 Beiträge
 
Delphi 10.1 Berlin Enterprise
 
#1

AW: Generisches ToString für Enumerations

  Alt 30. Apr 2011, 16:14
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.
Stefan
“Simplicity, carried to the extreme, becomes elegance.” Jon Franklin

Delphi Sorcery - DSharp - Spring4D - TestInsight
  Mit Zitat antworten Zitat
Benutzerbild von s.h.a.r.k
s.h.a.r.k

Registriert seit: 26. Mai 2004
3.159 Beiträge
 
#2

AW: Generisches ToString für Enumerations

  Alt 30. Apr 2011, 16:17
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 ) 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
»Remember, the future maintainer is the person you should be writing code for, not the compiler.« (Nick Hodges)

Geändert von s.h.a.r.k (30. Apr 2011 um 16:33 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Stevie
Stevie

Registriert seit: 12. Aug 2003
Ort: Soest
4.051 Beiträge
 
Delphi 10.1 Berlin Enterprise
 
#3

AW: Generisches ToString für Enumerations

  Alt 30. Apr 2011, 16:50
Du solltest die Größe deines Enum Typens überprüfen, der muss nämlich nicht immer 1 Byte sein.
Stefan
“Simplicity, carried to the extreme, becomes elegance.” Jon Franklin

Delphi Sorcery - DSharp - Spring4D - TestInsight
  Mit Zitat antworten Zitat
Benutzerbild von s.h.a.r.k
s.h.a.r.k

Registriert seit: 26. Mai 2004
3.159 Beiträge
 
#4

AW: Generisches ToString für Enumerations

  Alt 1. Mai 2011, 02:49
Du solltest die Größe deines Enum Typens überprüfen, der muss nämlich nicht immer 1 Byte sein.
Da hat der Herr wohl vollkommen recht, baue ich morgen ein Aber im großen und ganzen müsste das der Compiler sogar abfangen, da man ja einen Enum angeben muss, der im Moment ja immer 1 Byte groß ist. Bei den Enums, bei denen man Ordinalwerte angeben kann, wird ja eine Exception geworfen, da gar keine Typeinformationen vorhanden sind.

  1. Warum ein Record? Ernsthaft, wenn jmd irgendwo etwas sieht, was keine Klasse ist, wird er sich denken, dass es einen sehr guten Grund gab. Aber den gibt es hier überhaupt gar nicht.
    Solche ÖHM.... Momente haben in APIs nix zu suchen.
Ich habe es mir wahrlich im Source der VCL abgeschaut und versteh auch nicht den Sinn, warum ich das nicht machen sollte. Selbst TValue ist ein solcher Record, ebenso viele Dinge aus der neuen RTTI. Mir ist schon klar, wofür Records eigentlich gedacht sind, aber wo genau ist das Problem, dass ich Records verwende? Das kann dem Nutzer des Codes doch gänzlich egal sein, oder? Er ruft die Methode exakt gleich auf, bis auf dass anstatt record einfach class steht, was er eigentlich nicht sieht. Ich habe jetzt nicht das schlagende Argument gesehen, warum das denn unbedingt eine Klasse sein muss. Klar, man kann jetzt darüber streiten, was man mit Records alles machen können sollte und was nicht, aber ich sehe hier weniger ein Problem. Aber wie so oft, ich lasse mich gerne belehren
  1. Wenn du schon D2010 nutzt, dann nutze es auch.
    Ich habe es nicht ausprobiert und spreche den neuen Krams von Delphi nicht fließend, aber wenn ich eine generische Methode zum Wandeln in einen String ab D2010 schreiben müsste, würde das wohl so aussehen:
    TValue.From<T>(deinWert).AsString();
Okay, überzeugt. Habs gerade geändert. Allerdings geht das hier nicht: Result := TValue.From<String>(Value).AsType<T>; Endet in einer Exception:
Code:
Im Projekt Project1.exe ist eine Exception der Klasse EInvalidCast mit der Meldung 'Ungültige Typumwandlung' aufgetreten.
Hatte jetzt aber keine Lust mehr da lange zu testen
[...] oder eine erhoffte Optimierung nach Cargo-Cult Style. [...]
WTF? Was für ein Style?
»Remember, the future maintainer is the person you should be writing code for, not the compiler.« (Nick Hodges)
  Mit Zitat antworten Zitat
Elvis

Registriert seit: 25. Nov 2005
Ort: München
1.909 Beiträge
 
Delphi 2010 Professional
 
#5

AW: Generisches ToString für Enumerations

  Alt 1. Mai 2011, 09:37
Okay, überzeugt. Habs gerade geändert. Allerdings geht das hier nicht: Result := TValue.From<String>(Value).AsType<T>; Endet in einer Exception:
Code:
Im Projekt Project1.exe ist eine Exception der Klasse EInvalidCast mit der Meldung 'Ungültige Typumwandlung' aufgetreten.
Hatte jetzt aber keine Lust mehr da lange zu testen
Hmm, hatte mir nur TValue in den API Docs auf Embacadings.com angesehen. Hatte einfach erwartet dass es in beide Richtungen geht. Embarcadings scheint wohl auf Öhm-Momente in ihren APIs viel Wert zu legen, oder einfach nur keinen Anspruch zu haben...

Zitat:
[...] oder eine erhoffte Optimierung nach Cargo-Cult Style. [...]
WTF? Was für ein Style?
http://en.wikipedia.org/wiki/Cargo_c...mming#Overview
Robert Giesecke
I’m a great believer in “Occam’s Razor,” the principle which says:
“If you say something complicated, I’ll slit your throat.”
  Mit Zitat antworten Zitat
Benutzerbild von Stevie
Stevie

Registriert seit: 12. Aug 2003
Ort: Soest
4.051 Beiträge
 
Delphi 10.1 Berlin Enterprise
 
#6

AW: Generisches ToString für Enumerations

  Alt 1. Mai 2011, 10:52
Okay, überzeugt. Habs gerade geändert. Allerdings geht das hier nicht: Result := TValue.From<String>(Value).AsType<T>; Endet in einer Exception:
Code:
Im Projekt Project1.exe ist eine Exception der Klasse EInvalidCast mit der Meldung 'Ungültige Typumwandlung' aufgetreten.
Hatte jetzt aber keine Lust mehr da lange zu testen
Hmm, hatte mir nur TValue in den API Docs auf Embacadings.com angesehen. Hatte einfach erwartet dass es in beide Richtungen geht. Embarcadings scheint wohl auf Öhm-Momente in ihren APIs viel Wert zu legen, oder einfach nur keinen Anspruch zu haben...
Wie ich bereits sagte. In die eine Richtung geht es nur wegen dem ToString. Das wandelt alles in seine String Repräsentation um (genau wie das ToString in TObject). Es findet hier keine Typenkonvertierung statt. Bei deinem Versuch einen String in den Typen umzuwandeln bemüht die RTTI intern die Typenkonvertierung, sofern es sich um sehr ähnliche Typen handelt (Float typ, ordinal typ, etc). Und TValue ist nicht für eine Typenkonvertierung darüber hinaus gedacht und funktioniert auch nicht, wie du gesehen hast. Du kannst damit nichtmal nen string in nen integer umwandeln, obwohl das eigentlich technisch kein Probelm wäre.
Stefan
“Simplicity, carried to the extreme, becomes elegance.” Jon Franklin

Delphi Sorcery - DSharp - Spring4D - TestInsight

Geändert von Stevie ( 1. Mai 2011 um 10:54 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von s.h.a.r.k
s.h.a.r.k

Registriert seit: 26. Mai 2004
3.159 Beiträge
 
#7

AW: Generisches ToString für Enumerations

  Alt 1. Mai 2011, 13:33
Hmm, hatte mir nur TValue in den API Docs auf Embacadings.com angesehen. Hatte einfach erwartet dass es in beide Richtungen geht. Embarcadings scheint wohl auf Öhm-Momente in ihren APIs viel Wert zu legen, oder einfach nur keinen Anspruch zu haben...
Allein aufgrund der automatischen Garbage Collection bei Records kann ich verstehen, warum es so gemacht ist, wie es gemacht ist. Sonst müsstest du ja jedes mal ein TValue-Objekt erzeugen und freigeben, wenn du damit arbeiten willst. Records machen das halt sehr viel bequemer. Klar, in meinem Fall ändert sich nicht wirklich viel, aber ich hab mir mal den TValue-Record näher angeschaut und allein schon diese Zeile spricht für sich, wie ich finde:
Delphi-Quellcode:
TValue = record
public
  { ... }
  class function From<T>(const Value: T): TValue; static;
  { ... }
end;
Wäre TValue eine Klasse, dann müsste man die Speicherverwaltung teilweise intern, ebenso aber auch extern durch den Programmierer vornehmen, dass immer alles passt und keine Speicherleaks entstehen. Klar, man könnte den Record (bzw. dann evtl. die Klasse) anders gestalten, aber was genau spricht gegen eine solche Verwendung?

Ich bin echt gerne bereit, meine Ansichten zu ändern, wie schon gesagt, aber ich verstehe den Grund, warum ich das tun sollte, nicht wirklich?! Ich habe extra nochmals auf Wikipedia nachgelesen, wofür Records (bzw. Structs) eigentlich da sind, aber nachdem deren Funktionalität erweitert wurde, sehe ich weniger Probleme darin auch deren Vorteile zu verwenden.
»Remember, the future maintainer is the person you should be writing code for, not the compiler.« (Nick Hodges)
  Mit Zitat antworten Zitat
Benutzerbild von Stevie
Stevie

Registriert seit: 12. Aug 2003
Ort: Soest
4.051 Beiträge
 
Delphi 10.1 Berlin Enterprise
 
#8

AW: Generisches ToString für Enumerations

  Alt 1. Mai 2011, 14:10
Hmm, hatte mir nur TValue in den API Docs auf Embacadings.com angesehen. Hatte einfach erwartet dass es in beide Richtungen geht. Embarcadings scheint wohl auf Öhm-Momente in ihren APIs viel Wert zu legen, oder einfach nur keinen Anspruch zu haben...
Allein aufgrund der automatischen Garbage Collection bei Records kann ich verstehen, warum es so gemacht ist, wie es gemacht ist. Sonst müsstest du ja jedes mal ein TValue-Objekt erzeugen und freigeben, wenn du damit arbeiten willst. Records machen das halt sehr viel bequemer. Klar, in meinem Fall ändert sich nicht wirklich viel, aber ich hab mir mal den TValue-Record näher angeschaut und allein schon diese Zeile spricht für sich, wie ich finde:
Delphi-Quellcode:
TValue = record
public
  { ... }
  class function From<T>(const Value: T): TValue; static;
  { ... }
end;
Wäre TValue eine Klasse, dann müsste man die Speicherverwaltung teilweise intern, ebenso aber auch extern durch den Programmierer vornehmen, dass immer alles passt und keine Speicherleaks entstehen. Klar, man könnte den Record (bzw. dann evtl. die Klasse) anders gestalten, aber was genau spricht gegen eine solche Verwendung?

Ich bin echt gerne bereit, meine Ansichten zu ändern, wie schon gesagt, aber ich verstehe den Grund, warum ich das tun sollte, nicht wirklich?! Ich habe extra nochmals auf Wikipedia nachgelesen, wofür Records (bzw. Structs) eigentlich da sind, aber nachdem deren Funktionalität erweitert wurde, sehe ich weniger Probleme darin auch deren Vorteile zu verwenden.
Ihr redet aneinander vorbei. Bei TValue handelt es sich um einen Wertetypen. Bei deinem record nicht, denn er hat keinen State sondern nur 2 Methoden. Und dafür kann man auch ohne Probleme eine Klasse benutzen, weil man für die Benutzung von class methods nix instanzieren muss. Aber wie ich bereits sagte, spielt es für diesen konkreten Fall (Containertyp für parametriesierte Methoden) keine Rolle, ob du eine Klasse mit class methods nutzt oder einen record mit static methods.

Übrigens:
Du könntest auch einen record helper für TValue schreiben
Und schau dir mal die Implementierung von TRttiEnumerationType.GetValue in der Rtti.pas an.
Stefan
“Simplicity, carried to the extreme, becomes elegance.” Jon Franklin

Delphi Sorcery - DSharp - Spring4D - TestInsight

Geändert von Stevie ( 1. Mai 2011 um 14:27 Uhr)
  Mit Zitat antworten Zitat
Elvis

Registriert seit: 25. Nov 2005
Ort: München
1.909 Beiträge
 
Delphi 2010 Professional
 
#9

AW: Generisches ToString für Enumerations

  Alt 30. Apr 2011, 20:02
Wenn noch wer was dran auszusetzen hat, dann nur her damit
Klaro...
Delphi-Quellcode:
TEnumHelper = record
  class function EnumToStr<T>(Value: T): String; static;
  class function StrToEnum<T>(Value: String): T; static;
end;
  1. Warum ein Record? Ernsthaft, wenn jmd irgendwo etwas sieht, was keine Klasse ist, wird er sich denken, dass es einen sehr guten Grund gab. Aber den gibt es hier überhaupt gar nicht.
    Solche ÖHM.... Momente haben in APIs nix zu suchen.
  2. Wenn du schon D2010 nutzt, dann nutze es auch.
    Ich habe es nicht ausprobiert und spreche den neuen Krams von Delphi nicht fließend, aber wenn ich eine generische Methode zum Wandeln in einen String ab D2010 schreiben müsste, würde das wohl so aussehen:
    TValue.From<T>(deinWert).AsString();
Robert Giesecke
I’m a great believer in “Occam’s Razor,” the principle which says:
“If you say something complicated, I’ll slit your throat.”
  Mit Zitat antworten Zitat
Benutzerbild von Stevie
Stevie

Registriert seit: 12. Aug 2003
Ort: Soest
4.051 Beiträge
 
Delphi 10.1 Berlin Enterprise
 
#10

AW: Generisches ToString für Enumerations

  Alt 30. Apr 2011, 20:48
Warum ein Record? Ernsthaft, wenn jmd irgendwo etwas sieht, was keine Klasse ist, wird er sich denken, dass es einen sehr guten Grund gab. Aber den gibt es hier überhaupt gar nicht.
Solche ÖHM.... Momente haben in APIs nix zu suchen.
Wo ist der Unterschied einer statischen Klasse oder einem Rekord in diesem Fall?
Delphi unterstützt nämlich keine Typenparameter in einfachen Routinen.

Wenn du schon D2010 nutzt, dann nutze es auch.
Ich habe es nicht ausprobiert und spreche den neuen Krams von Delphi nicht fließend, aber wenn ich eine generische Methode zum Wandeln in einen String ab D2010 schreiben müsste, würde das wohl so aussehen:
Hier stimme ich dir vollstens zu, habe ich auch vorhin nicht mehr dran gedacht, sonst hätt ich es erwähnt
Dennoch kleine Korrektur: TValue.From<T>(Value).ToString denn AsString versucht, den Typen in einen string umzuwandeln, das wird fehlschlagen.
Stefan
“Simplicity, carried to the extreme, becomes elegance.” Jon Franklin

Delphi Sorcery - DSharp - Spring4D - TestInsight

Geändert von Stevie (30. Apr 2011 um 20:55 Uhr)
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


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 17:25 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