AGB  ·  Datenschutz  ·  Impressum  







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

Property via AsString;AsInteger;AsBoolean;.. laden

Ein Thema von -=ZGD=- · begonnen am 23. Aug 2012 · letzter Beitrag vom 24. Aug 2012
Antwort Antwort
Seite 1 von 4  1 23     Letzte »    
-=ZGD=-

Registriert seit: 25. Apr 2006
Ort: Bad Aibling
105 Beiträge
 
Delphi 10.1 Berlin Professional
 
#1

Property via AsString;AsInteger;AsBoolean;.. laden

  Alt 23. Aug 2012, 09:31
Servus,

ich stehe vor einem kleinen Problem und komm leider auch trotz Suche nicht auf die richtigen Stichwörter.
Ich bin mir sicher, dieses Problem wurde schon öfter mal angesprochen.

Problem

Ich habe eine Konfigurationsklasse, in welcher wie gesagt Einstellungen auf Vorrat gehalten werden.
Das Lesen/Schreiben via property Items[aKey: String]: String read GetValue write SetValue; in dem einfach der Schlüssel übergeben wird funktioniert problemlos.

Ich möchte jetzt aber nicht ständig Typenumwandlungen machen und daher ist meine Fragen:

Wie kann ich es lösen, dass der Aufruf myConfig.Items['dbport'].AsInteger genügen würde und ich den Port als Integer erhalten?

Über Links und Hilfestellung jeder Art bin ich dankbar.

Auch wenn wie hier die Antwort von mkinzler korrekt erscheint, mein Problem scheinbar beschreibt, hilft es absolut nicht weiter...

Ich danke vielmals.
Stefan Michalk
  Mit Zitat antworten Zitat
bepe

Registriert seit: 17. Okt 2006
118 Beiträge
 
#2

AW: Property via AsString;AsInteger;AsBoolean;.. laden

  Alt 23. Aug 2012, 09:45
Warum hilft dir die Antwort von mkinzler nicht weiter? Es ist nämlich die einzige Lösung die genau zu dem gewünschten Verhalten führt.

Deine Items müssten als Objekte in einem Array oder in einer Liste verwaltet werden. Dann könntest du über myConfig.Items['dbport'].WasAuchImmer auf die Methoden und Propertys zugreifen. Und du müsstest nur noch pro Datentyp eine Property mit entsprechender Getter Methode bereitstellen.

Alternativ könntest du auch weitere Propertys in deiner Config Klasse machen. Ungefähr so property ItemsAsInteger[aKey: String]: Integer read GetIntegerValue write SetIntegerValue; .

Aber du wirst zu jedem Datentyp eine Property samt Getter Methode schreiben müssen, welche sich dann um die Typumwandlung kümmert.

mfg,
bp
  Mit Zitat antworten Zitat
-=ZGD=-

Registriert seit: 25. Apr 2006
Ort: Bad Aibling
105 Beiträge
 
Delphi 10.1 Berlin Professional
 
#3

AW: Property via AsString;AsInteger;AsBoolean;.. laden

  Alt 23. Aug 2012, 09:49
Warum hilft dir die Antwort von mkinzler nicht weiter? Es ist nämlich die einzige Lösung die genau zu dem gewünschten Verhalten führt.
Weil "ja" mir nicht ausreichend war

Deine Items müssten als Objekte in einem Array oder in einer Liste verwaltet werden. Dann könntest du über myConfig.Items['dbport'].WasAuchImmer auf die Methoden und Propertys zugreifen. Und du müsstest nur noch pro Datentyp eine Property mit entsprechender Getter Methode bereitstellen.
Das wäre eigentlich genau mein Plan. Dann muss ich mit einer ObjectList arbeiten?

Alternativ könntest du auch weitere Propertys in deiner Config Klasse machen. Ungefähr so property ItemsAsInteger[aKey: String]: Integer read GetIntegerValue write SetIntegerValue; .

Aber du wirst zu jedem Datentyp eine Property samt Getter Methode schreiben müssen, welche sich dann um die Typumwandlung kümmert.
Hmm, auf diese Methode bin ich noch gar nicht gekommen. Der Implementierungsaufwand wäre in beiden Fällen der Gleiche...
Ich danke dir - einstweilen..
Stefan Michalk
  Mit Zitat antworten Zitat
bepe

Registriert seit: 17. Okt 2006
118 Beiträge
 
#4

AW: Property via AsString;AsInteger;AsBoolean;.. laden

  Alt 23. Aug 2012, 10:00
Weil "ja" mir nicht ausreichend war
Das hab ich mir fast gedacht Wollte eigentlich wissen wie ausführlich ich antworten sollte... Aber wenn du erst einmal weiter kommst, ist ja alles gut.

Die Variante mit den Objekten wäre meiner Meinung nach "schöner". Aber ist auch mit mehr Tipparbeit verbunden.

Die ObjectList wäre wohl eine gute Lösung. Aber es gibt (zumindest je nach Delphi Version) mehrere Ansätze. Da deine Items Namen haben, würde sich z.B. auch ein TDictionary anbieten.

mfg,
bp
  Mit Zitat antworten Zitat
-=ZGD=-

Registriert seit: 25. Apr 2006
Ort: Bad Aibling
105 Beiträge
 
Delphi 10.1 Berlin Professional
 
#5

AW: Property via AsString;AsInteger;AsBoolean;.. laden

  Alt 23. Aug 2012, 10:01
So sieht es jetzt bei mir aus

Ich habe ein record über alle Einträge:
Delphi-Quellcode:
type
  RConfig = record
    Key: String;
    Value: String;
  end;
Daraus einen eigenen Typ, als dynamisches Array

Delphi-Quellcode:
type
  TConfigList = array of RConfig;
Welches Verwendung in der Klassendeklaration
Delphi-Quellcode:
type
  TConfig = class(TObject)
  private
    Con: TZConnection;
    Query: TZQuery;

    fNewDB: Boolean;

    fList: TConfigList;

    function GetValue(aID: String): String;
    procedure SetValue(aID: String; aValue: String = '');
    function getItemCount: Integer;
  public
    constructor create;

    property IsNew: Boolean read fNewDB;
    property Items[aKey: String]: String read GetValue write SetValue;
    property Count: Integer read getItemCount;
    procedure ReadConfig;
    function Exists(aKey: String): Boolean;
    function save: Boolean;
  end;
in der privaten Variable fList Anwendung findet.

Wie würde jetzt meine Deklaration aussehen, wenn ich die Items als Objekt handhaben möchte.

Meine Idee wäre dann

Delphi-Quellcode:
type
  TConfigItem = class(TObject)
  private
    function GetAsInteger: Integer;
    function GetAsString: String;
  public
    property AsInteger: Integer read GetAsInteger;
    property AsString: String read GetAsString;
  end;
Woraus sich ergeben würde, dass Items[aKey: String]: TConfigItem wird.
Allerdings mit welchem read ?
Stefan Michalk
  Mit Zitat antworten Zitat
bepe

Registriert seit: 17. Okt 2006
118 Beiträge
 
#6

AW: Property via AsString;AsInteger;AsBoolean;.. laden

  Alt 23. Aug 2012, 10:18
So sieht es jetzt bei mir aus

Ich habe ein record über alle Einträge:
Delphi-Quellcode:
type
  RConfig = record
    Key: String;
    Value: String;
  end;
Daraus einen eigenen Typ, als dynamisches Array

Delphi-Quellcode:
type
  TConfigList = array of RConfig;
Soweit, so gut. Du brauchst jedoch nicht Objekt und Record. Du verwendest XE2? Dann kannst du in deinem Record Propertys deklarieren, wie du es auch in einem Objekt machen würdest.
Welches Verwendung in der Klassendeklaration
Delphi-Quellcode:
type
  TConfig = class(TObject)
  private
    Con: TZConnection;
    Query: TZQuery;

    fNewDB: Boolean;

    fList: TConfigList;

    function GetValue(aID: String): String;
    procedure SetValue(aID: String; aValue: String = '');
    function getItemCount: Integer;
  public
    constructor create;

    property IsNew: Boolean read fNewDB;
    property Items[aKey: String]: String read GetValue write SetValue;
    property Count: Integer read getItemCount;
    procedure ReadConfig;
    function Exists(aKey: String): Boolean;
    function save: Boolean;
  end;
in der privaten Variable fList Anwendung findet.

Wie würde jetzt meine Deklaration aussehen, wenn ich die Items als Objekt handhaben möchte.

Meine Idee wäre dann

Delphi-Quellcode:
type
  TConfigItem = class(TObject)
  private
    function GetAsInteger: Integer;
    function GetAsString: String;
  public
    property AsInteger: Integer read GetAsInteger;
    property AsString: String read GetAsString;
  end;
Wie erwähnt, du kannst die Funktionen und Propertys einfach ins Record verschieben und brauchst die Klasse nicht mehr. Aber ansonsten korrekt umgesetzt (wenn du nur lesend auf die Werte zugreifen möchtest).

Woraus sich ergeben würde, dass Items[aKey: String]: TConfigItem wird.
Allerdings mit welchem read ?
An der Deklaration von Items ändert sich, außer dem Typ, nichts. Also so wie du es gemacht hast*. Im read änderst du auch nur den Typ und greifst natürlich auf dein TConfigList array zu.

*Wenn du das Objekt entfernst und nur mit dem Record arbeitest, sehe Items so aus Items[aKey: String]: RConfig

mfg,
bp
  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: Property via AsString;AsInteger;AsBoolean;.. laden

  Alt 23. Aug 2012, 10:53
Schau dir dazu vielleicht auch mal die Operator-Überladung an, im speziellen Implicit. Damit bräuchtest du dann dieses AsString oder AsInteger nicht. Der Konvertierung würde dann alles automatisch funktionieren.

Besser für Refactoring wäre es, wenn du entsprechende Properties nutzen würdest. So handhabe ich das ganze -- momentan gibts den Code nur in VB.Net, portiere den aber bald nach Delphi:
Delphi-Quellcode:
// Habe die Property mal aufs Minimum reduziert
TXmlConfigurationNodeAttribute = class(TAttribute)
public
  property Path : string read GetPath;
end;

TBaseConfiguration = abstract class
protected
  FXmlPathToPropertyIndex : IDictionary<string, TRttiProperty>;
  
  // Diese Methode baut einen Index aus Pfad-zu-Property
  // Wertpaaren auf, welcher dann in der LoadConfiguration
  // genutzt wird
  procedure ReadXmlProperties();
public
  // Diese Methode liest aus dem XML-Node die entsprechenden
  // Daten aus und setzt die gelesenen Werte via RTTI auf die
  // entsprechenden Properties. Natürlich wird dabei eine
  // Konvertierung der Datentypen vorgenommen.
  procedure LoadConfiguration(XmlNode: IXmlNode);
end;

// Die Methode ist nur schnell hingeschrieben, die Idee soll
// rüberkommen!
procedure TBaseConfiguration.LoadConfiguration(XmlNode: IXmlNode);
begin
  for PathPropertyPair in FXmlPathToPropertyIndex
  begin
    Path := PathPropertyPair.Key;
    Property := PathPropertyPair.Value;
    Value := GetValueFromXml(XmlNode, Path);
    Property.SetValue(Self, Convert(Value, Property));
  end;
end;

// So, was bringt das nun? Je Anwendung brauche ich dann nur noch
// eine abgeleitete Klasse schreiben, die minimalen Code enthält,
// aber dennoch dafür sorgt, dass alles passt und dazu auch noch
// wunderbar typsicher ist.
TMyConfiguration = class(TBaseConfiguration)
public
  [XmlConfigurationNode('ftp-server/host')]
  property Host : string read FHost write SetHost;

  [XmlConfigurationNode('ftp-server/port')]
  property Port : Integer read FPort write SetPort;
end;
Vielleicht findest die Idee ja interessant
»Remember, the future maintainer is the person you should be writing code for, not the compiler.« (Nick Hodges)
  Mit Zitat antworten Zitat
Thom

Registriert seit: 19. Mai 2006
570 Beiträge
 
Delphi XE3 Professional
 
#8

AW: Property via AsString;AsInteger;AsBoolean;.. laden

  Alt 23. Aug 2012, 10:57
Wie wäre es mit dem Typ Variant als Ergebnis? Dann übernimmt Delphi die komplette Typ-Konvertierung (dort, wo es geht) und man spart sich viel Schreibarbeit:
Delphi-Quellcode:
type
  TMyClass = class
  private
    procedure SetItem(const Name: String; const Value: Variant);
    function GetItem(const Name: String): Variant;
  public
    property Items[const Name: String]: Variant read GetItem write SetItem;
  end;
Thomas Nitzschke
Google Maps mit Delphi
  Mit Zitat antworten Zitat
-=ZGD=-

Registriert seit: 25. Apr 2006
Ort: Bad Aibling
105 Beiträge
 
Delphi 10.1 Berlin Professional
 
#9

AW: Property via AsString;AsInteger;AsBoolean;.. laden

  Alt 23. Aug 2012, 10:59
Danke für dein Hilfe bepe.

Auf Grundlage deiner Informationen bin ich jetzt soweit vorangeschritten:

Delphi-Quellcode:
type
  RConfig2 = record
  private
    fKey: String;
    fValue: Variant;
    function GetAsString: String;
    function GetAsInteger: Integer;
  public
    property Key: String read fKey write fKey;
    property Value: Variant write fValue;
    property AsString: String read GetAsString;
    property AsInteger: Integer read GetAsInteger;
  end;
Die Implementierung der GET/SET

Delphi-Quellcode:
function RConfig2.GetAsString;
begin
  result := STRING(fValue);
end;

function RConfig2.GetAsInteger;
var
  val: Integer;
begin
  if TryStrToInt(fValue, val) then
  begin
    result := val
  end
  else
    raise Exception.Create('Konvertierungsfehler - Kein INTEGER');
end;

Daraus ergab sich eine neue Liste
Delphi-Quellcode:
type
  TConfigList2 = array of RConfig2;

Was im Objekt an sich zu folgenden Änderungen führt:

Delphi-Quellcode:
type
  TConfig = class(TObject)
  private
    ...
    fList: TConfigList;
    fList2: TConfigList2;

    ...
    function GetVariantValue(aID: String): RConfig2;
    procedure SetVariantValue(aID: string; aValue: Variant);

    ...
  public
    constructor create;

    ...
    property Item[aKey: String]: RConfig2 read GetVariantValue write SetVariantValue;
    ...
  end;
GetVariantValue sieht nun bei mir so aus (ja, noch keine Hashtable)

Delphi-Quellcode:
function TConfig.GetVariantValue(aID: string): RConfig2;
var
  i: Integer;
begin
  ReadConfig;
  for i := low(fList2) to high(fList2) do
  begin
    if uppercase(fList2[i].Key) = uppercase(aID) then
    begin
      Result := fList2[i];
      break;
    end;
  end;
end;
Ich dachte mir, ich nehme Variant als Typ für die Value, denn somit bin ich da flexibel...eher ungut?

Woran ich jetzt allerdings scheitere ist die Implementierung von SetVariantValue .

Der Compiler sagt
Code:
Inkompatible Typen
.

Delphi-Quellcode:
procedure Tconfig.SetVariantValue(aID: string; aValue: Variant);
begin

end;
Den Versuch, einfach ein
Code:
RConfig2
zu übergeben ist ebenfalls gescheitert.
Wo seh ich den Wald vor lauter Bäumen nicht? Ist die Implementierung in den Grundzügen so korrekt?
Stefan Michalk
  Mit Zitat antworten Zitat
-=ZGD=-

Registriert seit: 25. Apr 2006
Ort: Bad Aibling
105 Beiträge
 
Delphi 10.1 Berlin Professional
 
#10

AW: Property via AsString;AsInteger;AsBoolean;.. laden

  Alt 23. Aug 2012, 11:02
Wie wäre es mit dem Typ Variant als Ergebnis? Dann übernimmt Delphi die komplette Typ-Konvertierung (dort, wo es geht) und man spart sich viel Schreibarbeit:
Delphi-Quellcode:
type
  TMyClass = class
  private
    procedure SetItem(const Name: String; const Value: Variant);
    function GetItem(const Name: String): Variant;
  public
    property Items[const Name: String]: Variant read GetItem write SetItem;
  end;
Hallo Thom,

das würde funktionieren, ist aber insofern unpraktisch, dass ich gern vordefinierte Werte zurückgeben möchte.

Wenn ich beispielsweise einen Port (INTEGER) zuweise und die
Code:
Value
leer ist, beschmeißt mich Delphi natürlich mit der korrekten Fehlermeldung
Code:
"" ist kein gültiger Integer-Wert
. Das würde ich umgehen wollen und einfach von vorn herein
Code:
0
übergeben.
Stefan Michalk
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 4  1 23     Letzte »    


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 08:20 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