AGB  ·  Datenschutz  ·  Impressum  







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

Typeinfo als Parameter

Ein Thema von hanspeter · begonnen am 6. Nov 2013 · letzter Beitrag vom 6. Nov 2013
Antwort Antwort
hanspeter

Registriert seit: 26. Jul 2003
Ort: Leipzig
1.350 Beiträge
 
Delphi XE2 Professional
 
#1

Typeinfo als Parameter

  Alt 6. Nov 2013, 10:36
Delphi-Version: XE2
Hallo,
ich bin dabei ein altes Projekt von D5 auf XE2 zu portieren.

In diesem Projekt wird sehr viel mit records gearbeitet.
Diese enthalten Shortstrings (z.B. String[40]).
Solche Records werden dann in Memory und/oder Filestreams abgelegt.

Um von den Ansistrings wegzukommen probiere ich mehrere Möglichkeiten.

Was funktioniert ist einmal ein neuer Datentyp z.B. TFixedstring.
Delphi-Quellcode:
type
  TFixString = record
    Value: array[0..41] of Char;
    class operator implicit(const aValue: string): TFixString;
    class operator implicit(const aValue: TFixString): string;
  end;
Das bedeutet aber, dass für jede vorhandene Stringlänge ein eigener Datentyp
declariert werden muss.

String[22] -> Fixstring22
String[40] -> Fixstring40
String[128] -> Fixstring 128 ...

Die 2. Möglichkeit ist die Ergänzung eines Record mit einer Methode write/readstream.
Hier kann Variable und Dateninhalt über Rtti ausgelesen werden.
Beispiel:

Delphi-Quellcode:
function TNodeData.ToString: String;
var
    AContext : TRttiContext;
    AField : TRttiField;
    ARecord : TRttiRecordType;
    AFldName : String;
    AValue : TValue;
begin
    Result := '';
    AContext := TRttiContext.Create;
    try
        ARecord := AContext.GetType(TypeInfo(TNodeData)).AsRecord;
        for AField in ARecord.GetFields do begin
            AFldName := AField.Name;
            AValue := AField.GetValue(@Self);
            Result := Result + AFldName + '|"' +
                      EscapeQuotes(AValue.ToString) + '";';
        end;
    finally
        AContext.Free;
    end;
end;
Beide Varianten bedingen, dass jeder record angepasst werden muss.

Was ich bauen möchte ist eigentlich eine Klasse z.B. TDatastream.
Eine Methode TDatastream.Write(const rec) sollte den Record in einem Stream schreiben
Jetzt suche ich eine Lösung um die Rtti Informationen von rec als typloser Parameter auszulesen.
Hat wer da eine Idee?

Gruß
Peter
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.184 Beiträge
 
Delphi 12 Athens
 
#2

AW: Typeinfo als Parameter

  Alt 6. Nov 2013, 11:41
Zitat:
FixStringXX
So weit war ich auch schon, aber leider sind da auch die Generics zu nix zu gebrauchen.
Und aus irgendwelchen Gründen wehren sich Alle gegen die Einführung von Makros, bzw. daß man Konstanten als "Parameter" in den Generics verwenden kann.
Delphi-Quellcode:
TFixString<Len> = record
  Value: array[0..Len-1] of Char;
  class operator implicit(const aValue: string): TFixString;
  class operator implicit(const aValue: TFixString): string;
end;


Zitat:
Jetzt suche ich eine Lösung um die Rtti Informationen von rec als typloser Parameter auszulesen.
P{Pointer} := TypeInfo(TNodeData); kannst du problemlos als Parameter an deine Funktion übergen, oder hab ich dein Problem falsch verstanden?

Du könntest auch TReader und TWriter verwenden, so wie es z.B. die VCL mit den binären DFMs macht.
Dort wurd zu jedem "Wert" auch der Typ mit gespeichert, was das Auslesen von "unbekannten" Datenstrukturen ermöglicht.
Wenn man da Feldname+Wert abspeichet, dann kann man beim Auslesen die Daten sogar in einen anderen Record/Datenobjekt übertragen, da man den Feld-/Propertynamen kennt.
- so kann man Speicher sparen, da man "unnötige" Daten weglässt (in der DFM stehen ja auch nur "abweichende" Property drin)
- wenn man das ausgelesene Feld über seinen Namen sucht, passiert nichts, wenn man an der Struktur des Records was verändert (neue Felder irgendwo einfügen oder Alte entfernen)
$2B or not $2B
  Mit Zitat antworten Zitat
Benutzerbild von uligerhardt
uligerhardt

Registriert seit: 19. Aug 2004
Ort: Hof/Saale
1.746 Beiträge
 
Delphi 2007 Professional
 
#3

AW: Typeinfo als Parameter

  Alt 6. Nov 2013, 13:39
In diesem Projekt wird sehr viel mit records gearbeitet.
Diese enthalten Shortstrings (z.B. String[40]).
Solche Records werden dann in Memory und/oder Filestreams abgelegt.

Um von den Ansistrings wegzukommen probiere ich mehrere Möglichkeiten.
Das Problem haben wir auch. Finde ich schwach vom Emba, dass sie keinen UnicodeString[N] eingebaut haben. Das wäre für den Compilerbauer IMNSHO um einiges leichter zu implementieren gewesen und mit besserem Ergebnis als eine drangefrickelte Lösung von dir oder mir.

Das bedeutet aber, dass für jede vorhandene Stringlänge ein eigener Datentyp declariert werden muss.

String[22] -> Fixstring22
String[40] -> Fixstring40
String[128] -> Fixstring 128 ...
Macht doch nix - dass lässt sich doch mit Suchen und Ersetzen gut lösen.

Zitat:
FixStringXX
So weit war ich auch schon, aber leider sind da auch die Generics zu nix zu gebrauchen.
Und aus irgendwelchen Gründen wehren sich Alle gegen die Einführung von Makros, bzw. daß man Konstanten als "Parameter" in den Generics verwenden kann.
Delphi-Quellcode:
TFixString<Len> = record
  Value: array[0..Len-1] of Char;
  class operator implicit(const aValue: string): TFixString;
  class operator implicit(const aValue: TFixString): string;
end;
Da vermisse ich mal wieder C++ und Templates. Was in Delphi halbwegs als Ersatz geht, ist statt direkt der Größe einen Typ passender Größe zu übergeben:
Delphi-Quellcode:
TFixString<TMitPassenderLaenge: record> = record
  Value: array[0..SizeOf(TMitPassenderLaenge)-1] of Char; // Achtung: SizeOf liefert gelegentlich 0
  // oder
  Value: array[0..1] of TMitPassenderLaenge; // danach fleißig casten. :-(
end;
und
Delphi-Quellcode:
Str40 = string[40];
FixString40 = TFixString<Str40>;
oder
Delphi-Quellcode:
Arr40 = Array[0..39] of AnsiChar;
FixString40 = TFixString<Arr40>;
Nicht elegant, aber besser als nix.
Uli Gerhardt

Geändert von uligerhardt ( 6. Nov 2013 um 13:43 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.184 Beiträge
 
Delphi 12 Athens
 
#4

AW: Typeinfo als Parameter

  Alt 6. Nov 2013, 14:28
Sowas ginge auch, aber diese "brutalen" Castst machen keinen Spaß, vorallem Dank der massiven Bugs beim SizeOf. (dann lieber copy&paste)
Delphi-Quellcode:
TFixString<Arr> = record
  Value: Arr;
  class operator implicit(const aValue: string): TFixString;
  class operator implicit(const aValue: TFixString): string;
end;

//Arr40 = array[0..39] of WideChar;
//FixString40 = TFixString<Arr40>;
  FixString40 = TFixString<array[0..39] of WideChar>;
$2B or not $2B

Geändert von himitsu ( 6. Nov 2013 um 14:30 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von uligerhardt
uligerhardt

Registriert seit: 19. Aug 2004
Ort: Hof/Saale
1.746 Beiträge
 
Delphi 2007 Professional
 
#5

AW: Typeinfo als Parameter

  Alt 6. Nov 2013, 14:38
Sowas ginge auch, aber diese "brutalen" Castst machen keinen Spaß, vorallem Dank der massiven Bugs beim SizeOf. (dann lieber copy&paste)
Mit Delphi macht DRY manchmal keinen Spaß.
Uli Gerhardt
  Mit Zitat antworten Zitat
Furtbichler
(Gast)

n/a Beiträge
 
#6

AW: Typeinfo als Parameter

  Alt 6. Nov 2013, 15:07
Um von den Ansistrings wegzukommen probiere ich mehrere Möglichkeiten.
Wenn Du die alten Daten verarbeiten musst, spricht doch nichts dagegen, die einzulesenden Strings explizit als AnsiString zu deklarieren. So steht es nun einmal in der Datei drin (wenn es denn eine Datei ist).

Vielleicht legst Du pro Record eine String-Property an, die diese AnsiStrings konvertiert, eventuell auch als lazy load (wenn Performance eine Rolle spielt).

Ich habe das allerdings mal so gelöst, das meine 'Records' nun Klassen sind. Jede Klasse hat eine Load und Store Methode, die die einzelnen Daten/Felder bytegenau ausliest bzw. abspeichert, und zwar genauso, wie das der Record gemacht hat.

Aus Bockread(myFile, @myRecord, SizeOf(myRecord)) wird dann MyClass.Load(myFileStream); . Das ist zwar ein wenig Arbeit, aber nur 1x und straight forward. Für die einzelnen Load/Store-Methoden schreibe ich Unit-Tests, um sicherzugehen, das die Daten genauso abgelegt/gelesen werden, wie der Record.

Ich mach mir da keine großen Gedanken um Generics oder tolle allgemeingültige Lösungen. So ein TFixString<irgendwas> ist doch schwer zu lesen und bringt eigentlich auch nicht viel.
  Mit Zitat antworten Zitat
hanspeter

Registriert seit: 26. Jul 2003
Ort: Leipzig
1.350 Beiträge
 
Delphi XE2 Professional
 
#7

AW: Typeinfo als Parameter

  Alt 6. Nov 2013, 19:32
Erst mal danke für die Tips.

Ich werde wohl Record gegen Class auswechseln müssen.
Dadurch das records nicht erben können, gibt es keinen Vorfahr end eine typlose Übergabe funktioniert nicht richtig.
Da die Record sequentiell in einem Memorystream gespeichert und ausgelesen werden, habe ich jetzt eine andere Lösung gefunden, die funktioniert.
Ich habe mir eine Datenstreamklasse gebaut. Diese hat gleichnamige Methoden wie die TMemorystreamklasse. Es werden allerdings Klassreferenzern in einer TObjectliste verwaltet.
Das funktioniert erst mal.
Die Umsetzung von Ansi auf Unicode kann man in Delphi ja nicht gerade als gelungen bezeichnen.
Abgesehen von unterschiedlichen Datentypen bei string und string[] , herrscht auch in der stringbibliothek ein ziemliches Wirrwar.
Genauso gut könnte man Integer als 4 byt und Array of integer als jeweils 2 Byte implementieren.
Ich hoffe ja das der Mobile Hype bei Embarcadero bald vorbei ist und es bei Delphi selbst wieder mal ein paar Fortschritte gibt.


Gruß Peter
  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 22:10 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