Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Automatischer Setter/Getter für Aufzählungs-Variablen via RTTI? (https://www.delphipraxis.net/194103-automatischer-setter-getter-fuer-aufzaehlungs-variablen-via-rtti.html)

freejay 17. Okt 2017 13:47

Automatischer Setter/Getter für Aufzählungs-Variablen via RTTI?
 
Hallo zusammen,

wenn ich ein String-Property
Code:
MySet
habe und ein zugehöriges Feld
Code:
FMySet
vom Typ
Code:
TMySet = (Hund,Katze,Maus)
dann muss ich manuell einen GETter und einen SETter dafür schreiben. Und sobald neue Ausprägunge dazu kommen (z.B. Giraffe, Känguru), dann muss ich jedesmal auch die Get- und Set-Routinen erweitern.

Und das ist eine ziemlich lästige aber/und primitive Aufgabe, da es dabei eigentlich immer nur um ein

Code:
else if Value = "Katze" then
  FMySet := Katze
else...
geht.

Müsste es nicht möglich sein, mit Hilfe der RTTI universelle Getter und Setter für Aufzählungstypen zu entwickeln, die die verfügbaren Werte als String ermitteln können und daher in einer Schleife für beliebige Aufzählungen funktionieren würden?

Ich habe mich bislang nicht viel mit der RTTI beschäftigt und hätte - bevor ich mich da voll reinhänge - gerne von Erfahreneren eine Einschätzung dazu.

Danke im Voraus & sonnige Grüße aus Nürnberg ;-)

Freejay

Stevie 17. Okt 2017 14:02

AW: Automatischer Setter/Getter für Aufzählungs-Variablen via RTTI?
 
IMO solltest du lieber das eigentliche Problem lösen, nämlich, dass du für eine begrenzte Menge an Möglichkeiten (enum) eine Eigenschaft vom Typ string hast und nicht vom Typ deines enums.

Trotzdem noch etwas zu deiner Frage - klar, kann man irgendwie mit RTTI drauf schießen, ist aber imo unnötig. Delphi bietet die Möglichkeit, konstane statische Arrays über einen Enum zu definieren.

Delphi-Quellcode:
uses
  StrUtils,
  SysUtils;

type
  TPet = (Hund,Katze,Maus);

const
  CPetNames: array[TPet] of string = ('Hund','Katze','Maus');

function TryGetEnumValue(const s: string; out value: TPet): Boolean;
var
  i: Integer;
begin
  i := IndexText(s, CPetNames);
  Result := i > -1;
  if Result then
    value := TPet(i);
end;
Das ganze kann man natürlich auch generisch und über RTTI lösen, aber dann muss man sich was überlegen, ob aus dem enum Wert die entsprechenden Namen zu ermitteln, sollten die mal nicht 1-zu-1 zusammen passen oder lokalisierbar sein.

Aber nochmal, ich würd lieber mit dem enum Typ arbeiten und erst dort, wo man einen string benötigt (z.B. in der UI) umwandeln. Ansonsten hat man ein "stringly typed" System.

nahpets 17. Okt 2017 14:08

AW: Automatischer Setter/Getter für Aufzählungs-Variablen via RTTI?
 
Meinst Du sowas?
Delphi-Quellcode:
uses
  Classes,
  TypInfo;

{ Die Prozedur liefert Informationen zum übergebenen Aufzählungstypen und gibt }
{ diese in der Stringliste zurück.                                            }
procedure TRTTI.GetEnumTypeInfo(AClass: TObject);
begin
  GetEnumTypeInfo(PTypeInfo(AClass));
end;

{ Die Prozedur liefert Informationen zum übergebenen Aufzählungstypen und gibt }
{ diese in der Stringliste zurück.                                            }
procedure TRTTI.GetEnumTypeInfo(ATypeInfo: PTypeInfo);
var
  OrdTypeData : PTypeData;
  TypeNameStr : String;
  TypeKindStr : String;
  MinVal     : Integer;
  MaxVal     : Integer;
  i          : integer;
begin
  // TTypeData-Pointer holen
  OrdTypeData := GetTypeData(ATypeInfo);
  // Typnamen holen
  TypeNameStr := ATypeInfo.Name;
  // Typart als String holen
  TypeKindStr := GetEnumName(TypeInfo(TTypeKind), Integer(ATypeInfo^.Kind));
  // Niedrigsten und höchstmöglichen Wert holen
  MinVal := OrdTypeData^.MinValue;
  MaxVal := OrdTypeData^.MaxValue;
  // Informationen in Stringliste übernehmen
  FHtml.Add('<ul class="dot">');
  FHtml.Add('<li><em class="Name">Type Name: ' + TypeNameStr + '</em></li>');
  FHtml.Add('<li><em class="Kind">Type Kind: ' + TypeKindStr + '</em></li>');
  // Der gibt zuweilen seltsame Abstürze, das Programm ist einfach weg.
  If ATypeInfo^.Kind in [tkInteger, tkChar, tkEnumeration, tkFloat, tkInt64] Then Begin
    FHTML.Add('<li style="list-style: none">');
    FHtml.Add('<ul class="dot">');
    FHtml.Add('<li><em class="MinMax">Min Val: ' + IntToStr(MinVal) + '</em></li>');
    FHtml.Add('<li><em class="MinMax">Max Val: ' + IntToStr(MaxVal) + '</em></li>');
    // Mögliche Werte und Namen von Aufzählungstypen holen
    // WordBool geht als Aufzählungstyp von -2147483648 bis 2147483647.
    // Das ist etwas zuviel, um alle Werte aufzulisten.
    if (ATypeInfo^.Kind = tkEnumeration) And (UpperCase(TypeNameStr) <> 'WORDBOOL') then Begin
      FHTML.Add('<li style="list-style: none">');
      FHtml.Add('<table class="small">');
      Try
        // Eigentlich sollte man meinen, das MinVal kleiner als MaxVal ist,
        If MinVal < MaxVal Then Begin
          for i := MinVal to MaxVal do Begin
            FHtml.Add('<tr><td class="left" width="10%"><ul class="dot"><li><em class="Value">Value: ' + IntToStr(i) + '</em></li></ul></td>'
                        + '<td class="left" width="30%"><ul class="dot"><li><em class="Value">Name: ' + GetEnumName(ATypeInfo, i) + '</em></li></ul></td></tr>');
          End;
        End Else Begin // ist es aber bei TOleEnum nicht
          for i := MinVal Downto MaxVal do Begin
            FHtml.Add('<tr><td class="left" width="10%"><ul class="dot"><li><em class="Value">Value: ' + IntToStr(i) + '</em></li></ul></td>'
                        + '<td class="left" width="30%"><ul class="dot"><li><em class="Value">Name: ' + GetEnumName(ATypeInfo, i) + '</em></li></ul></td></tr>');
          End;
        End;
      Except
        FHtml.Add('<tr><td>Values nicht zu ermitteln.</td></tr>');
      End;
      FHtml.Add('</table>');
      FHtml.Add('</li>');
    End;
    FHtml.Add('</ul>');
    FHtml.Add('</li>');
  End Else Begin
  End;
  FHtml.Add('</ul>');
end;
Ist ein Fragment aus einer Klasse, mit der ich mir die Dokumantation eines Programmes, einer Klasse ... über RTTI generiere und mit Delphi 7 geschrieben.

freejay 17. Okt 2017 14:19

AW: Automatischer Setter/Getter für Aufzählungs-Variablen via RTTI?
 
Zitat:

Zitat von Stevie (Beitrag 1383530)
IMO solltest du lieber das eigentliche Problem lösen, nämlich, dass du für eine begrenzte Menge an Möglichkeiten (enum) eine Eigenschaft vom Typ string hast und nicht vom Typ deines enums.

Trotzdem noch etwas zu deiner Frage - klar, kann man irgendwie mit RTTI drauf schießen, ist aber imo unnötig. Delphi bietet die Möglichkeit, konstane statische Arrays über einen Enum zu definieren.

Delphi-Quellcode:
uses
  StrUtils,
  SysUtils;

type
  TPet = (Hund,Katze,Maus);

const
  CPetNames: array[TPet] of string = ('Hund','Katze','Maus');

function TryGetEnumValue(const s: string; out value: TPet): Boolean;
var
  i: Integer;
begin
  i := IndexText(s, CPetNames);
  Result := i > -1;
  if Result then
    value := TPet(i);
end;
Das ganze kann man natürlich auch generisch und über RTTI lösen, aber dann muss man sich was überlegen, ob aus dem enum Wert die entsprechenden Namen zu ermitteln, sollten die mal nicht 1-zu-1 zusammen passen oder lokalisierbar sein.

Aber nochmal, ich würd lieber mit dem enum Typ arbeiten und erst dort, wo man einen string benötigt (z.B. in der UI) umwandeln. Ansonsten hat man ein "stringly typed" System.

Ich benutze ja den Enum Typ. Nur in der Kommunikation nach aussen (eingelesene bzw. rausgeschriebene Daten) brauche ich dann einen String.

Dein Vorschlag würde die Anzahl Stellen, an denen etwas gemacht werden muss (wenn neue Werte hinzukommen) immerhin schon mal von 3 auf 2 reduzieren und den pro-Wert-Aufwand zusätzlich verringern.

Was mich an dieser (und erst recht an meiner) Lösung trotzdem noch stört, ist, dass ich quasi die gleichen Texte zweimal (bei mir: drei mal) im Code aufführen und ergänzen muss (Hund und 'Hund')...

freejay 17. Okt 2017 14:23

AW: Automatischer Setter/Getter für Aufzählungs-Variablen via RTTI?
 
Zitat:

Zitat von nahpets (Beitrag 1383531)
Meinst Du sowas?
Delphi-Quellcode:
...
Ist ein Fragment aus einer Klasse, mit der ich mir die Dokumantation eines Programmes, einer Klasse ... über RTTI generiere und mit Delphi 7 geschrieben.

Danke: Das muss ich mir erstmal ausführlicher ansehen... Im Moment sehe ich nur überall HTML-Tags... ;-)

nahpets 17. Okt 2017 14:32

AW: Automatischer Setter/Getter für Aufzählungs-Variablen via RTTI?
 
Ungetestet EntHTMLisiert und GeShowMessaged ;-)
Delphi-Quellcode:
uses
  Classes,
  TypInfo;

{ Die Prozedur liefert Informationen zum übergebenen Aufzählungstypen. }
procedure TRTTI.GetEnumTypeInfo(AClass: TObject);
begin
  GetEnumTypeInfo(PTypeInfo(AClass));
end;

{ Die Prozedur liefert Informationen zum übergebenen Aufzählungstypen. }
procedure TRTTI.GetEnumTypeInfo(ATypeInfo: PTypeInfo);
var
  OrdTypeData : PTypeData;
  TypeNameStr : String;
  TypeKindStr : String;
  MinVal : Integer;
  MaxVal : Integer;
  i : integer;
begin
  // TTypeData-Pointer holen
  OrdTypeData := GetTypeData(ATypeInfo);
  // Typnamen holen
  TypeNameStr := ATypeInfo.Name;
  // Typart als String holen
  TypeKindStr := GetEnumName(TypeInfo(TTypeKind), Integer(ATypeInfo^.Kind));
  // Niedrigsten und höchstmöglichen Wert holen
  MinVal := OrdTypeData^.MinValue; // Kleinster Wert
  MaxVal := OrdTypeData^.MaxValue; // Höchster Wert
  // Type Name = TypeNameStr
  // Type Kind = TypeKindStr
  If ATypeInfo^.Kind in [tkInteger, tkChar, tkEnumeration, tkFloat, tkInt64] Then Begin
    if (ATypeInfo^.Kind = tkEnumeration) And (UpperCase(TypeNameStr) <> 'WORDBOOL') then Begin
      Try
        // Eigentlich sollte man meinen, das MinVal kleiner als MaxVal ist,
        If MinVal < MaxVal Then Begin
          for i := MinVal to MaxVal do Begin
            // Verbale Beschreibung = GetEnumName(ATypeInfo, i) // Also z. B. Hund
            ShowMessage(GetEnumName(ATypeInfo, i));
          End;
        End Else Begin // ist es aber bei TOleEnum nicht
          for i := MinVal Downto MaxVal do Begin
            // Verbale Beschreibung = GetEnumName(ATypeInfo, i) // Also z. B. Hund
            ShowMessage(GetEnumName(ATypeInfo, i));
          End;
        End;
      Except
        // Fehlerbehandlung
      End;
    End;
  End;
end;

freejay 17. Okt 2017 14:36

AW: Automatischer Setter/Getter für Aufzählungs-Variablen via RTTI?
 
Zitat:

Zitat von freejay (Beitrag 1383535)
Zitat:

Zitat von nahpets (Beitrag 1383531)
Meinst Du sowas?
Delphi-Quellcode:
...
Ist ein Fragment aus einer Klasse, mit der ich mir die Dokumantation eines Programmes, einer Klasse ... über RTTI generiere und mit Delphi 7 geschrieben.

Danke: Das muss ich mir erstmal ausführlicher ansehen... Im Moment sehe ich nur überall HTML-Tags... ;-)

Ja, das könnte mir helfen.

Werde ich "die Tage" mal ausprobieren.

Vielen Dank!

freejay 17. Okt 2017 14:38

AW: Automatischer Setter/Getter für Aufzählungs-Variablen via RTTI?
 
Zitat:

Zitat von nahpets (Beitrag 1383537)
Ungetestet EntHTMLisiert und GeShowMessaged ;-)
Delphi-Quellcode:
uses
  Classes,
  TypInfo;

{ Die Prozedur liefert Informationen zum übergebenen Aufzählungstypen. }
procedure TRTTI.GetEnumTypeInfo(AClass: TObject);
begin
  GetEnumTypeInfo(PTypeInfo(AClass));
end;

{ Die Prozedur liefert Informationen zum übergebenen Aufzählungstypen. }
procedure TRTTI.GetEnumTypeInfo(ATypeInfo: PTypeInfo);
var
  OrdTypeData : PTypeData;
  TypeNameStr : String;
  TypeKindStr : String;
  MinVal : Integer;
  MaxVal : Integer;
  i : integer;
begin
  // TTypeData-Pointer holen
  OrdTypeData := GetTypeData(ATypeInfo);
  // Typnamen holen
  TypeNameStr := ATypeInfo.Name;
  // Typart als String holen
  TypeKindStr := GetEnumName(TypeInfo(TTypeKind), Integer(ATypeInfo^.Kind));
  // Niedrigsten und höchstmöglichen Wert holen
  MinVal := OrdTypeData^.MinValue; // Kleinster Wert
  MaxVal := OrdTypeData^.MaxValue; // Höchster Wert
  // Type Name = TypeNameStr
  // Type Kind = TypeKindStr
  If ATypeInfo^.Kind in [tkInteger, tkChar, tkEnumeration, tkFloat, tkInt64] Then Begin
    if (ATypeInfo^.Kind = tkEnumeration) And (UpperCase(TypeNameStr) <> 'WORDBOOL') then Begin
      Try
        // Eigentlich sollte man meinen, das MinVal kleiner als MaxVal ist,
        If MinVal < MaxVal Then Begin
          for i := MinVal to MaxVal do Begin
            // Verbale Beschreibung = GetEnumName(ATypeInfo, i) // Also z. B. Hund
            ShowMessage(GetEnumName(ATypeInfo, i));
          End;
        End Else Begin // ist es aber bei TOleEnum nicht
          for i := MinVal Downto MaxVal do Begin
            // Verbale Beschreibung = GetEnumName(ATypeInfo, i) // Also z. B. Hund
            ShowMessage(GetEnumName(ATypeInfo, i));
          End;
        End;
      Except
        // Fehlerbehandlung
      End;
    End;
  End;
end;

Oh danke! :thumb: Das wär doch nicht nötig gewesen... :oops:

nahpets 17. Okt 2017 14:42

AW: Automatischer Setter/Getter für Aufzählungs-Variablen via RTTI?
 
Wieso nicht, das Original ist ja nun mal auch unübersichtlich ;-)

Wesentlich wäre: Liefert die die Routine ansatzweise im ShowMessage solche Werte, wie Du erwartest?

Ansonsten ist's ja vergeblich :-(

Oh, da fand ich noch dashier: http://www.swissdelphicenter.ch/de/showcode.php?id=389

freejay 17. Okt 2017 14:58

AW: Automatischer Setter/Getter für Aufzählungs-Variablen via RTTI?
 
Das kann ich frühestens morgen testen.
Gebe dann nochmal Rückmeldung.
Danke nochmal!


Alle Zeitangaben in WEZ +1. Es ist jetzt 14:44 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