Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Delphi Property -> Getter und Setter mit Parametern (https://www.delphipraxis.net/183678-property-getter-und-setter-mit-parametern.html)

bernau 28. Jan 2015 08:59

Property -> Getter und Setter mit Parametern
 
Ein Gedankengang zum Thema "wie spare ich Tipperei".

Ich habe ein CustomObject, welches Parameter speichert. Egal wo und wie. Und es gibt eine Ableitung in der ich einige Properties definiere, welche Properties des Parent verwendet. Der Zugriff wird in der Implementation geregelt.

Delphi-Quellcode:
interface

type
  TCustomSpeicherobjekt = class(TObject)
    private
      function GetEinStringWert(aIndex: string): string;
      procedure SetEinStringWert(aIndex: string; const Value: string);
    public
      property EinStringWert[aIndex:string]:string read GetEinStringWert write SetEinStringWert;
    end;


  TMeinSpeicherobjekt = class(TCustomSpeicherobjekt)
    private
      function GetWertA: string;
      function GetWertB: string;
      procedure SetWertA(const Value: string);
      procedure SetWertB(const Value: string);
    public
      property WertA:string read GetWertA write SetWertA;
      property WertB:string read GetWertB write SetWertB;
    end;


implementation

{ TMeinSpeicherobjekt }

function TCustomSpeicherobjekt.GetEinStringWert(aIndex: string): string;
begin
  // Hier steht Code zum Lesen
end;

procedure TCustomSpeicherobjekt.SetEinStringWert(aIndex: string; const Value: string);
begin
  // Hier steht Code zum Schreiben
end;


{ TMeinSpeicherobjekt }

function TMeinSpeicherobjekt.GetWertA: string;
begin
  Result:=EinStringWert['WertA'];
end;

function TMeinSpeicherobjekt.GetWertB: string;
begin
  Result:=EinStringWert['WertB'];
end;

procedure TMeinSpeicherobjekt.SetWertA(const Value: string);
begin
  EinStringWert['WertA']:=Value;
end;

procedure TMeinSpeicherobjekt.SetWertB(const Value: string);
begin
  EinStringWert['WertB']:=Value;
end;
Gibt es einge Möglichkeit den Code zu verkürzen. Ich denke an so etwas wie die direkte Funktionsübergabe mit Parameter. Dann könnte man sich die Implementation sparen.

Beispiel:

Delphi-Quellcode:
  TMeinSpeicherobjekt = class(TCustomSpeicherobjekt)
    private
    public
      // Entweder so
      property WertA:string read EinStringWert['WertA'] write EinStringWert['WertA'];
      // oder so
      property WertB:string read GetEinStringWert('WertB') write SetEinStringWert('WertB');
    end;
Oder gibt es andere Ansätze?

Sherlock 28. Jan 2015 09:10

AW: Property -> Getter und Setter mit Parametern
 
Eventuell hilft Dir index als Indexbezeichner. Schau Dir die Hilfe zu properties nochmal an.

http://docwiki.embarcadero.com/RADSt...dex_Specifiers

Sherlock

jaenicke 28. Jan 2015 09:27

AW: Property -> Getter und Setter mit Parametern
 
Ich würde dann aber die Stringindizes nicht nach außen geben, um Tippfehler zu minimieren und das z.B. so lösen (wenn die Stringindizes intern notwendig sind):
Delphi-Quellcode:
{$SCOPEDENUMS ON}

type
  TCustomSpeicherobjekt = class(TObject)
  private
    function GetEinStringWert(aIndex: string): string;
    procedure SetEinStringWert(aIndex: string; const Value: string);
  public
    property EinStringWert[aIndex: string]: string read GetEinStringWert write SetEinStringWert;
  end;

  TMeinSpeicherobjekt = class(TCustomSpeicherobjekt)
  public type
    TValueInfo = (ValueA, ValueB);
  private
    const
      cValueNames: array[TValueInfo] of string = ('WertA', 'WertB');
    function GetValue(ValueKind: TValueInfo): string;
    procedure SetValue(ValueKind: TValueInfo; const Value: string);
  public
    property Value[ValueKind: TValueInfo]: string read GetValue write SetValue;
  end;

implementation

{ TMeinSpeicherobjekt }

function TCustomSpeicherobjekt.GetEinStringWert(aIndex: string): string;
begin
  // Hier steht Code zum Lesen
end;

procedure TCustomSpeicherobjekt.SetEinStringWert(aIndex: string; const Value: string);
begin
  // Hier steht Code zum Schreiben
end;

{ TMeinSpeicherobjekt }

function TMeinSpeicherobjekt.GetValue(ValueKind: TValueInfo): string;
begin
  Result := EinStringWert[cValueNames[ValueKind]];
end;

procedure TMeinSpeicherobjekt.SetValue(ValueKind: TValueInfo; const Value: string);
begin
  EinStringWert[cValueNames[ValueKind]] := Value;
end;
Dann lässt sich das einfach so nutzen:
Delphi-Quellcode:
MyObject.Value[TValueKind.ValueA] := 'Test';
ShowMessage(MyObject.Value[TValueKind.ValueA]);

bernau 28. Jan 2015 10:01

AW: Property -> Getter und Setter mit Parametern
 
Zitat:

Zitat von Sherlock (Beitrag 1288029)
Eventuell hilft Dir index als Indexbezeichner. Schau Dir die Hilfe zu properties nochmal an.[/url]

Ne, das ist nicht wirklich optimal. Ein index ist nicht sprechend und zu fehleranfällig. Wenn der Index ein String sein könnte, dann wäre es eine Lösung

Ich suche eine Lösung, in der ich die Implementation übergehen kann.

bernau 28. Jan 2015 10:04

AW: Property -> Getter und Setter mit Parametern
 
Zitat:

Zitat von jaenicke (Beitrag 1288031)
Dann lässt sich das einfach so nutzen:
Delphi-Quellcode:
MyObject.Value[TValueKind.ValueA] := 'Test';
ShowMessage(MyObject.Value[TValueKind.ValueA]);

Auch nicht wirklich eine alternative. Ich nutze gerne Codevervollständigung. Da möchte ich das Property direkt verwenden.

Sir Rufo 28. Jan 2015 10:24

AW: Property -> Getter und Setter mit Parametern
 
Zitat:

Zitat von bernau (Beitrag 1288036)
Zitat:

Zitat von Sherlock (Beitrag 1288029)
Eventuell hilft Dir index als Indexbezeichner. Schau Dir die Hilfe zu properties nochmal an.[/url]

Ne, das ist nicht wirklich optimal. Ein index ist nicht sprechend und zu fehleranfällig. Wenn der Index ein String sein könnte, dann wäre es eine Lösung

Ich suche eine Lösung, in der ich die Implementation übergehen kann.

Dieser Index ist aber die einzige Moglichkeit um im Getter/Setter zu erfahren, welche Eigenschaft denn nun diesen aufgerufen hat. So einfach ist das.

Dieser Index kann ein Integer oder ein Enum sein.

uligerhardt 28. Jan 2015 10:36

AW: Property -> Getter und Setter mit Parametern
 
Zitat:

Zitat von Sir Rufo (Beitrag 1288043)
Dieser Index kann ein Integer oder ein Enum sein.

... und er taucht im Anwender-Code ja gar nicht auf. (Was ja AFAICT bernaus Befürchtung ist.)

bernau 28. Jan 2015 11:26

AW: Property -> Getter und Setter mit Parametern
 
OK. Ich verbuche das einfach mal unter "geht nicht".

Uwe Raabe 28. Jan 2015 11:58

AW: Property -> Getter und Setter mit Parametern
 
Zitat:

Zitat von bernau (Beitrag 1288050)
OK. Ich verbuche das einfach mal unter "geht nicht".

Vielleicht nicht genau so, wie du das gern hättest. Allerdings gibt es genügend Möglichkeiten, dir die Tipparbeit zu ersparen.

Eine davon ist der Einsatz des ModelMaker Code Explorer, den ich in solchen Fällen ja gern als sinnvolles Werkzeug in der IDE anführe. Hier bieten sich verschiedene Möglichkeiten an, um die Tipparbeit einzusparen. Die einfachste ist, man legt einmal ein solches Property "WertA" an und implementiert den Zugriff, wobei der IndexString exakt dem Property-Namen entspricht (wie im Beispiel gezeigt). Dann kopiert man das Property mit dem MMX und benutzt dessen Member-Inplace-Rename-Funktionalität, um das neue Property in "WertB" umzubenennen. Erfreulicherweise werden dabei auch die IndexStrings mit umbenannt.

Eine andere Alternative ist das Anlegen eines eigenen Getter/Setter-Templates, das dann bei einem neuen Property zum Einsatz kommt.

Aber es geht auch ohne MMX mit dem Vorschlag von jaenicke, wenn man ihn etwas abwandelt (das SCOPEDENUMS ist hier nicht unbedingt notwendig):

Delphi-Quellcode:
  TMeinSpeicherobjekt = class(TCustomSpeicherobjekt)
  private type
    {$SCOPEDENUMS ON}
    TValueInfo = (WertA, WertB);
    {$SCOPEDENUMS OFF}
  protected
    function GetValue(ValueKind: TValueInfo): string;
    procedure SetValue(ValueKind: TValueInfo; const Value: string);
  public
    property WertA: string index TValueInfo.WertA read GetValue write SetValue;
    property WertB: string index TValueInfo.WertB read GetValue write SetValue;
  end;

uses
  System.TypInfo;

function TMeinSpeicherobjekt.GetValue(ValueKind: TValueInfo): string;
begin
  result := EinStringWert[GetEnumName(TypeInfo(TValueInfo), Ord(ValueKind))];
end;

procedure TMeinSpeicherobjekt.SetValue(ValueKind: TValueInfo; const Value: string);
begin
  EinStringWert[GetEnumName(TypeInfo(TValueInfo), Ord(ValueKind))] := Value;
end;

bernau 28. Jan 2015 13:27

AW: Property -> Getter und Setter mit Parametern
 
@Uwe: Das ist ein Ansatz, der sehr interessant aussieht.

Sir Rufo 28. Jan 2015 14:10

AW: Property -> Getter und Setter mit Parametern
 
Zitat:

Zitat von bernau (Beitrag 1288069)
@Uwe: Das ist ein Ansatz, der sehr interessant aussieht.

Das meinte ich mit den Enums ... nur so nebenbei bemerkt :)

Dejan Vu 28. Jan 2015 20:32

AW: Property -> Getter und Setter mit Parametern
 
Wenn man weniger Tipparbeit haben will, würde ich mal die Programmiersprache wechseln. :stupid:

Diese Klimmzüge, um Getter und Setter über indexe anzusprechen, ist doch ziemlich unsauber und irgendwie von hinten durch die Brust ins Auge. Denn was habe ich im Getter und Setter vermutlich? Ein Case, würde ich mal annehmen. Oder halten wir die Daten etwa in einem Array?

Uwe Raabe 28. Jan 2015 22:04

AW: Property -> Getter und Setter mit Parametern
 
Zitat:

Zitat von Dejan Vu (Beitrag 1288125)
Denn was habe ich im Getter und Setter vermutlich? Ein Case, würde ich mal annehmen. Oder halten wir die Daten etwa in einem Array?

Ein Array oder eine StringList oder sonst eine Struktur, die über einen Index angesprochen werden kann. In diesem Fall könnte ich mir auch eine Name-Value-Liste oder ein Dictionary vorstellen. Ein case halte ich für ziemlich unwahrscheinlich - habe ich jedenfalls noch nie gesehen. Ist aber vollkommen irrelevant, denn der Getter ist ja gerade dazu da, die tatsächliche Implementierung zu kapseln.

sx2008 28. Jan 2015 22:28

AW: Property -> Getter und Setter mit Parametern
 
Delphi-Quellcode:
TCustomSpeicherobjekt = class(TObject)
private
   function GetEinStringWert(aIndex: string): string;
   procedure SetEinStringWert(aIndex: string; const Value: string);
public
   property EinStringWert[aIndex:string]:string read GetEinStringWert write SetEinStringWert;default;
end;
Der Property EinStringWert ist ein Array-Property.
Pro Klasse kann man genau ein Array-Property zum Default-Indexer erklären (Schlüsselwort default).
Delphi-Quellcode:
var
   x : TCustomSpeicherobjekt;
begin
   x := TCustomSpeicherobjekt.Create;
   x['Host'] := 'www.delphipraxis.net';
Das spart auch Tipparbeit.

Dejan Vu 29. Jan 2015 06:48

AW: Property -> Getter und Setter mit Parametern
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1288127)
Ein Array oder eine StringList oder sonst eine Struktur, die über einen Index angesprochen werden kann. In diesem Fall könnte ich mir auch eine Name-Value-Liste oder ein Dictionary vorstellen.

Das hat ja dann meistens etwas mit Persistenz zu tun und -wupps- habe ich wieder Zuständigkeiten vermischt.

Und selbst wenn es nichts mit Persistenz zu tun hat, ist es unsauber, denn die Tatsache, das der Wert 'FooBar' an Stelle 3 im Array stehen soll, ist somit an mehreren Stellen definiert. Ausnahme: Das Array ist ein Ersatz für private Felder. D.h. im Getter/Setter steht nur der Zugriff auf das Array. Dann...Nun ja. Spart man keine Tipparbeit, sondern hat einen Mapper geschrieben.

Die Motivation des TE ist TIPPARBEIT SPAREN und nicht, Konstrukte für Index-Properties zu finden, die sinnvoll sind.

Zitat:

Zitat von Uwe Raabe (Beitrag 1288127)
Ein case halte ich für ziemlich unwahrscheinlich - habe ich jedenfalls noch nie gesehen. Ist aber vollkommen irrelevant, denn der Getter ist ja gerade dazu da, die tatsächliche Implementierung zu kapseln.

Wer Tipparbeit sparen will, macht leider Folgendes (z.B.):
Delphi-Quellcode:
Procedure TMyClass.SetValue (Value : TSomeType;Index : Integer);
begin
  case Index of
    0 : StringValues[0] := Value.AsString;
    1 : IntegerValues[0] := Value.AsInteger;
  ...
end;
Das Beispiel stammt aus meinem uralten Code. Kapselung dient ja nicht dazu, schlechten Code zu verbergen. Sollte es zumindest nicht.


Zitat:

Zitat von sx2008 (Beitrag 1288130)
Delphi-Quellcode:
var
   x : TCustomSpeicherobjekt;
begin
   x := TCustomSpeicherobjekt.Create;
   x['Host'] := 'www.delphipraxis.net';
Das spart auch Tipparbeit.

'Host' wird ja noch an einer anderen Stelle verwendet (beim Lesen nämlich). Und wenn man sich beim 'Host' vertippt hat? Meckert der Compiler natürlich nicht und es führt zu Laufzeitfehlern, die schwer zu finden sind. Beispiel: 'Нost' vs. 'Host' (Das 'H' im ersten Host wurde von meinem russischen Kollegen getippt).

Delphi ist nun mal eine Programmiersprache, die von Tastaturherstellern gesponsort wird...

Sherlock 29. Jan 2015 07:56

AW: Property -> Getter und Setter mit Parametern
 
Zitat:

Zitat von Dejan Vu (Beitrag 1288134)
Delphi ist nun mal eine Programmiersprache, die von Tastaturherstellern gesponsort wird...

Ich dachte immer, das war Assembler. Aber die Zeiten ändern sich wohl.

Sherlock

bernau 29. Jan 2015 10:48

AW: Property -> Getter und Setter mit Parametern
 
Nochmal danke für die Beiträge. Letztendlich gibt es nicht das, was ich mir vorgestellt habe. War ja auch nur ein Gedankengang.

Wichtig ist für mich, daß die Properties bestehen bleiben. Deshalb fällt der Vorschlag von z.B. sx2008 aus.

Ausserdem muss der Code lesbar bleiben. Deshalb wäre ein Sprachfeature in der Form von

Delphi-Quellcode:
// Entweder so
property WertA:string read EinStringWert['WertA'] write EinStringWert['WertA'];
// oder so
property WertB:string read GetEinStringWert('WertB') write SetEinStringWert('WertB');
eine tolle Sache. Damit wäre Tipparbeit erheblich reduziert und der Code ist besonders gut lesbar.


Der Vorschlag von "Uwe Raabe" wäre der besste. Allerdings auch nur, wenn keine Sonderzeichen benötigt werden. Folgendes wäre damit nicht möglich.

Delphi-Quellcode:
property WertA:string read EinStringWert['Wert-A-MitSonderzeichen'] write EinStringWert['Wert-A-MitSonderzeichen'];


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