Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Property als Array (https://www.delphipraxis.net/47453-property-als-array.html)

malo 11. Jun 2005 13:07


Property als Array
 
Hi!

Ich habe ein kleines Problem... und zwar will ich eine Property als Array verwenden. Ich hab es so versucht:

Delphi-Quellcode:
property Operators[Ndx: integer]: String read fOperators write fOperators;
fOperators ist dabei ein array of string. Ich bekomm dann jedoch den Fehler "inkompatible Typen: 'dynamic Array' und 'Procedure'".

Ich hab auch versucht, den Index von der Property wegzulassen. Ändert jedoch nichts...

Aus der Fehlermeldung schließe ich, dass ich die Get- und Set-Methode mit einer Prozedur ausführen muss...

Aber wie genau funktioniert das ganze dann? :gruebel:

jfheins 11. Jun 2005 13:13

Re: Property als Array
 
Delphi-Referenz durchsuchenArray-Properties ;)

Khabarakh 11. Jun 2005 13:15

Re: Property als Array
 
Schreib doch einfach
Delphi-Quellcode:
property Operators[Ndx: integer]: String read GetOperators write SetOperators;
und drück Strg + Shift + C, dann macht Delphi schon die halbe Arbeit :wink: .

leddl 11. Jun 2005 13:21

Re: Property als Array
 
Um ein Item des Array zu bekommen, greifst du einfach über die getMethode darauf zu:
Delphi-Quellcode:
function getArrayItem(Index : Integer) : String;
Begin
//Bereichsprüfung nicht vergessen!
if (Index > -1) and (Index < high(fArray)) Then
  result := fArray[Index];
else
//Oder was auch immer, vielleicht sogar ne Exception,...
  result := '';
End;
Analog bei der setMethode. Um ein neues Item hinzuzufügen brauchst du dann halt ne extra Methode.

Khabarakh 11. Jun 2005 13:27

Re: Property als Array
 
Zitat:

Zitat von leddl
Um ein Item des Array zu bekommen, greifst du einfach über die getMethode darauf zu:
Delphi-Quellcode:
function getArrayItem(Index : Integer) : String;
Begin
//Bereichsprüfung nicht vergessen!
if (Index > -1) and (Index < high(fArray)) Then
  result := fArray[Index];
else
//Oder was auch immer, vielleicht sogar ne Exception,...
  result := '';
End;
Analog bei der setMethode. Um ein neues Item hinzuzufügen brauchst du dann halt ne extra Methode.

Müsste es nicht
Delphi-Quellcode:
if (Index > -1) and (Index <= High(fArray)) then
heißen :gruebel: ?

malo 11. Jun 2005 13:34

Re: Property als Array
 
Mein Code bis jetzt:

Delphi-Quellcode:
type
  TTokens = class
    private
      fOperators: array of string;
      function GetOperators(Index: integer): string;
      procedure SetOperators(Index: integer; s: string);
    public
      property Operators[Ndx: integer]: String read GetOperators write SetOperators;
  end;
//...

procedure TTokens.SetOperators(Index: integer; s: string);
begin
  if Index < high(fOperators) then
    fOperators[Index] := s;
end;

function TTokens.GetOperators(Index: integer): string;
begin
if (Index > -1) and (Index <= high(fOperators)) Then
  result := fOperators[Index]
else
  result := '';
end;
Ist das so richtig (bis auf den fehlenden Else-Zweig in der Set-Methode)? Und wie muss ich die Add-Methode implementieren? :gruebel:

jfheins 11. Jun 2005 13:35

Re: Property als Array
 
Nein, du prüft beim Setter wieder ein element zu wenig. mach am besten bei beidem < length () ;)

leddl 11. Jun 2005 15:46

Re: Property als Array
 
@Khabarakh:
Jupp, das is mir durchgeflutscht ;)

@malo:
Bei ner Add-Methode mußt du einfach nur an das Array ein neues Element anhängen...

Robert_G 11. Jun 2005 16:16

Re: Property als Array
 
Zitat:

Zitat von leddl
@malo:
Bei ner Add-Methode mußt du einfach nur an das Array ein neues Element anhängen...

Genau DAS sollte man nicht machen. ;)
Wenn es eine array-basierte Liste sein soll sollte man sie stufenweise vergrößern. ;)
Eine Vergrößerung auf 172% der alten Größe hat sich als bester Allroundwert gezeigt. Bei kleinen Datenmengen wäre es möglich den ersten Sprung relativ großzügig ausfallen zu lassen, dadurch würde man sich vielleicht kleine weitere Kopiererei antun müssen.
Außerdem verstehe ich diese Liste von "Operatoren" nicht ganz...

Eine Liste von Tokens könnte, um es ganz plain & easy zu machen, so aussehen:
Delphi-Quellcode:
type
   TToken = class
   // was immer du damit machen willst ;-)
   end;

   TTokenClass = class of TToken;
Delphi-Quellcode:
type
   TTokenListInherited = class(TObjectList)
  protected
      function getItem(aIndex: Integer): TToken; virtual;
      procedure setItem(aIndex: Integer; aToken: TToken); virtual;
   public
      function Add(aToken: TToken): Integer; virtual;
      function Remove(aToken: TToken): Integer; virtual;
      function IndexOf(aToken: TToken): Integer; virtual;
      function FindInstanceOf(aClass: TTokenClass;
                              aExact: Boolean = True;
                              aStartAt: Integer = 0): Integer; virtual;
      procedure Insert(aIndex: Integer; aToken: TToken); virtual;
      function First: TToken; virtual;
      function Last: TToken; virtual;
      property Items[Index: Integer]: TToken read getItem write setItem; default;
   end;

implementation

{ TTokenListInherited }

function TTokenListInherited.Add(aToken: TToken): Integer;
begin
   Result := inherited Add(aToken);
end;

function TTokenListInherited.FindInstanceOf(aClass: TTokenClass; aExact: Boolean;
   aStartAt: Integer): Integer;
begin
   Result := FindInstanceOf(aClass, aExact, aStartAt);
end;

function TTokenListInherited.First: TToken;
begin
   Result := inherited First() as TToken;
end;

function TTokenListInherited.getItem(aIndex: Integer): TToken;
begin
   Result := inherited GetItem(aIndex) as TToken;
end;

function TTokenListInherited.IndexOf(aToken: TToken): Integer;
begin
   Result := inherited IndexOf(aToken);
end;

procedure TTokenListInherited.Insert(aIndex: Integer; aToken: TToken);
begin
   inherited Insert(aIndex, aToken);
end;

function TTokenListInherited.Last: TToken;
begin
   Result := inherited Last() as TToken;
end;

function TTokenListInherited.Remove(aToken: TToken): Integer;
begin
   Result := inherited Remove(aToken);
end;

procedure TTokenListInherited.setItem(aIndex: Integer; aToken: TToken);
begin
   inherited setItem(aIndex, aToken);
end;
Da Tlist seine Methoden nicht virtual deklariert hat, ist es nicht möglich diese zu überschreiben um auf den Typen zu testen. :?
Es ist also möglich, die Liste auf TObjectList oder einen Vorfahren zu casten und einfach etwas anderes als einen Nachfahren von TToken reinzuwerfen.
Möglich wäre es also TObjectList zu verwenden anstatt davon abzuleiten.
Dadurch kannst du dir sicher sein, dass nur TToken Instanzen in die InnerList gelangen können.
Wie im oberen Beispiel ist keinerlei zusätzliche Logik nötig, da diese bereits von TList / TObjectList bereitgestellt wird. ;)
Delphi-Quellcode:
type
   TObjectListClass = class of TObjectList;

   TTokenListNotInherited = class
   private
      fInnerList: TObjectList;
   protected
      property InnerList: TObjectList read fInnerList;
      function getItem(aIndex: Integer): TToken; virtual;
      procedure setItem(aIndex: Integer; aToken: TToken); virtual;
   public
      function Add(aToken: TToken): Integer; virtual;
      function Remove(aToken: TToken): Integer; virtual;
      function IndexOf(aToken: TToken): Integer; virtual;
      function FindInstanceOf(aClass: TTokenClass;
                              aExact: Boolean = True;
                              aStartAt: Integer = 0): Integer; virtual;
      procedure Insert(aIndex: Integer; aToken: TToken); virtual;
      function First: TToken; virtual;
      function Last: TToken; virtual;
      property Items[Index: Integer]: TToken read getItem write setItem; default;
      procedure Clear; virtual;  

      constructor Create(); overload;virtual;
      constructor Create(aListClass :TObjectListClass); overload;virtual;
   end;

implementation

{ TTokenListNotInherited }

constructor TTokenListNotInherited.Create;
begin
   fInnerList := TObjectList.Create(True);
end;

constructor TTokenListNotInherited.Create(aListClass :TObjectListClass);
begin
   fInnerList := aListClass.Create(True);
end;

function TTokenListNotInherited.Add(aToken: TToken): Integer;
begin
   Result := InnerList.Add(aToken);
end;

procedure TTokenListNotInherited.Clear;
begin
   InnerList.Clear();
end;

function TTokenListNotInherited.FindInstanceOf(aClass: TTokenClass; aExact: Boolean;
   aStartAt: Integer): Integer;
begin
   Result := InnerList.FindInstanceOf(aClass, aExact, aStartAt);
end;

function TTokenListNotInherited.First: TToken;
begin
   Result := InnerList.First() as TToken;
end;

function TTokenListNotInherited.getItem(aIndex: Integer): TToken;
begin
   Result := InnerList[aIndex] as TToken;
end;

function TTokenListNotInherited.IndexOf(aToken: TToken): Integer;
begin
   Result := InnerList.IndexOf(aToken);
end;

procedure TTokenListNotInherited.Insert(aIndex: Integer; aToken: TToken);
begin
   InnerList.Insert(aIndex, aToken);
end;

function TTokenListNotInherited.Last: TToken;
begin
   Result := InnerList.Last() as TToken;
end;

function TTokenListNotInherited.Remove(aToken: TToken): Integer;
begin
   Result := InnerList.Remove(aToken);
end;

procedure TTokenListNotInherited.setItem(aIndex: Integer; aToken: TToken);
begin
   InnerList[aIndex] := aToken;
end;
Der zweite Weg ist zwar gehörig hässlich aber hat nicht die Lücke des oberen. ;)
btw: TList suckz :P

malo 11. Jun 2005 16:41

Re: Property als Array
 
:shock: Das ist ja ein ganz schöner Brocken...

Naja, manchmal kommt mir schon mal die bekannte Frage auf: Warum einfach, wenn es auch kompliziert geht? :gruebel:

Meine "Liste von Operatoren" ist dafür da, dass man für meine "Programmiersprache" Operatoren hinzufügen bzw. prüfen kann.

Das ganze hab ich gemacht, weil ich in diese Liste jeden Operator reinschreiben wollte, den es in dieser "Programmiersprache" geben sollte. Bei meinem Tokenizer sollte dann geprüft werden, ob das jeweilige Zeichen meines Sourcecodes ein Operator ist.

Dafür die "Liste von Operatoren". Ich könnte natürlich auch eine Konstantenarray verwenden, aber ich weiß nicht, inwieweit ich meine Sprache noch erweitern will. Daher wollte ich ein variables Array nehmen. Und wegen der OOP wollte ich halt nicht unbedingt Public-Variablen verwenden, sondern lieber eine Property.


Und ich gehe nicht für eine solch kleine Liste so große Umwege wie Robert mir vorschlagen will. Manches ist echt zu viel des Guten. Ich bin dir zwar sehr dankbar für deine Mühen, Robert, aber ich verstehe einfach nicht, wofür all das notwendig ist. Ich persöhnlich komme jederzeit auch gut mit einem einfachen Array klar. Wozu also eine TObjectList UND eine Klasse, in der die meisten (oder alle?) der ObjectList-Methoden drin vorkommen, die im Endeffekt nur die gleiche Methode einer echten TObjectList aufrufen. Ich halte sowas nicht nur für unnötig, sondern auch noch für Zeitverschwendung.

Sorry, aber das musste einfach mal raus. Man muss nicht für ALLES eine eigene Klasse haben.

Robert_G 11. Jun 2005 19:18

Re: Property als Array
 
Das Ding hieß TTokens, deshalb dachte ich du packst dort deine Tokens rein.
Interessant wäre ab dem Punkt, wenn du unterschiedliche Tokenarten von TToken ableitest (Operatoren, Typen, Keywords,...).
Und so kompliziert ist das gar nicht. ;) Es gibt doch Ctrl+Shift+C , effektiv habe ich an jeder Lister bestimmt weniger als 30 Zeilen getippt. Von denen ein Großteil der Buchstaben durch Code completion reingefumpt wurde. ;)

Die Verwendung ist halt mega einfach und darum gates doch eigentlich, oder? :zwinker:

Zitat:

Wozu also eine TObjectList UND eine Klasse, in der die meisten (oder alle?) der ObjectList-Methoden drin vorkommen, die im Endeffekt nur die gleiche Methode einer echten TObjectList aufrufen. Ich halte sowas nicht nur für unnötig, sondern auch noch für Zeitverschwendung.
Der Sinn ist type safety. Du bekommst nicht nur einen compilerfehler, wenn man etwas falsches reinwirft, du musst auch keine Type casts mehr machen. ;)
Man darf das Wort Zeitverschwendung nicht so überstrapazieren. Es kostet wenige Minuten diese strong typed ObjectList zu tippen (wesentlich weniger Zeit als du für den letzten Absatz gebraucht hast :P ), aber bei jeder Verwendung sparst du dir Typecasts und ein paar Prüfungen. :zwinker:

Verstehe mich nicht falsch, ich will dich hier in keine Ecke drängen.
Ich hatte eigentlich nur das TTokens falsch interpretiert und nun musste ich einfach zur "Zeitverschwendung" Stellung nehmen...

malo 11. Jun 2005 19:49

Re: Property als Array
 
Hi Robert!
Zitat:

Zitat von Robert_G
Das Ding hieß TTokens, deshalb dachte ich du packst dort deine Tokens rein.

Stimmt auch. Die Klasse ist auch etwas größer, ich hab aber nur die Methoden/Properties drin gelassen, die für das Problem relevant sind. ;)


Zitat:

Zitat von Robert_G
Interessant wäre ab dem Punkt, wenn du unterschiedliche Tokenarten von TToken ableitest (Operatoren, Typen, Keywords,...).

Auch das mach ich schon. Ich unterscheide im Moment schon zwischen Zahlen, Bezeichner (Typen, Keywords etc.), Strings und Variablen (die mit einem $ eingeleitet werden und daher seperat ausgewertet werden können). Das ganze ist jedoch nur der erste Schritt. Im zweiten Schritt des Parsens unterscheide ich zwischen bestimmten Bezeichnern (prüfe, ob es ein Keyword ist oder vielleicht doch ein Operator wie beispielsweise not, oder vielleicht doch eine Funktion/Prozedur.


Zitat:

Zitat von Robert_G
Und so kompliziert ist das gar nicht. ;) Es gibt doch Ctrl+Shift+C , effektiv habe ich an jeder Lister bestimmt weniger als 30 Zeilen getippt. Von denen ein Großteil der Buchstaben durch Code completion reingefumpt wurde. ;)

Tja, Ctrl+Shift+C funktioniert schonmal bei meinen PE-Versionen nicht (ich hab zwar D5 Pro, aber die Version benutz ich nicht so gerne, da die nicht so ganz legal ist (eine SSL-Version von meinem Bruder. Ich hab keine eigene Lizenz dafür)).

Zitat:

Zitat von Robert_G
Zitat:

Wozu also eine TObjectList UND eine Klasse, in der die meisten (oder alle?) der ObjectList-Methoden drin vorkommen, die im Endeffekt nur die gleiche Methode einer echten TObjectList aufrufen. Ich halte sowas nicht nur für unnötig, sondern auch noch für Zeitverschwendung.
Der Sinn ist type safety. Du bekommst nicht nur einen compilerfehler, wenn man etwas falsches reinwirft, du musst auch keine Type casts mehr machen. ;)
Man darf das Wort Zeitverschwendung nicht so überstrapazieren. Es kostet wenige Minuten diese strong typed ObjectList zu tippen (wesentlich weniger Zeit als du für den letzten Absatz gebraucht hast :P ), aber bei jeder Verwendung sparst du dir Typecasts und ein paar Prüfungen. :zwinker:

Wie gesagt: Ich komme notfalls auch mit einem einfach Array aus. Ganz davon zu schweigen, dass ich von Type Casts KEINE Ahnung habe...

Ich will ja nur Strings in der Liste speichern. Es würde also ein Array of String auch tun. Wofür also eine extra Klasse erstellen, wenn es auch leichter geht? Klar, um die ewigen SetLength's zu vermeiden könnte man noch eine Add-Methode implementieren, aber mehr ist ehrlich nicht nötig.

Zitat:

Zitat von Robert_G
Verstehe mich nicht falsch, ich will dich hier in keine Ecke drängen.
Ich hatte eigentlich nur das TTokens falsch interpretiert und nun musste ich einfach zur "Zeitverschwendung" Stellung nehmen...

Ich fühle mich auch nicht in die Ecke gedrängt. Ich halte es einfach nur für unnötig, einen solchen Aufwand zu betreiben, wenn es halt viel einfacher geht. Ich sehe da keinen Sinn drin.

Und ich gebe zu, die "Zeitverschwendung" scheint weniger Aufwand zu sein, als ich zuerst dachte.

Ich bin dir natürlich sehr dankbar, wenn du dir nähere Gedanken zu meinem "Problem" machst und auch für Vorschläge offen. Aber manche Sachen halte ich einfach für unnötig und übertrieben. ;)

SirThornberry 11. Jun 2005 20:24

Re: Property als Array
 
zur Ausgangsfrage - Wenn "fOperators" bereits ein Array of String ist wozu machst du dann noch die eckigen klammern bei deinem property?
Delphi-Quellcode:
property Operators[Ndx: integer]: String read fOperators write fOperators;
Denn wenn fOperators bereits das Array ist hättest du ja sonst ein 2 dimensionales.

am einfachsten ohne Get und SetMethode wäre es da doch
Delphi-Quellcode:
Type
  TDynStringArr = Array of String;
[...]
private
fOperators: TDynStringArr;
[...]
property Operators: TDynStringArr read fOperators write fOperators;

malo 11. Jun 2005 20:31

Re: Property als Array
 
Zitat:

Zitat von SirThornberry
zur Ausgangsfrage - Wenn "fOperators" bereits ein Array of String ist wozu machst du dann noch die eckigen klammern bei deinem property?
Delphi-Quellcode:
property Operators[Ndx: integer]: String read fOperators write fOperators;
Denn wenn fOperators bereits das Array ist hättest du ja sonst ein 2 dimensionales.

am einfachsten ohne Get und SetMethode wäre es da doch
Delphi-Quellcode:
Type
  TDynStringArr = Array of String;
[...]
private
fOperators: TDynStringArr;
[...]
property Operators: TDynStringArr read fOperators write fOperators;

:wall: Danke, so scheints auch zu gehen ;)

Nogge 7. Aug 2005 18:00

Re: Property als Array
 
Dazu eine Frage: Wieso kann ich nicht einfach
Delphi-Quellcode:
public
Operators: Array of String;
anstelle einer zusätzlichen (unnötigen?) property schreiben?

malo 7. Aug 2005 18:08

Re: Property als Array
 
Zitat:

Zitat von Nogge
Dazu eine Frage: Wieso kann ich nicht einfach
Delphi-Quellcode:
public
Operators: Array of String;
anstelle einer zusätzlichen (unnötigen?) property schreiben?

Nunja, eine Property würde beispielsweise auch die Speicherzuweisung übernehmen können und sowas... ist halt kein Muss, aber es ist halt "OOP-Konform". Alles eine Frage des Programmierstils, denke ich. Ich wollte es damals so haben, und habs dann auch so gemacht :)

DevilsCamp 25. Aug 2005 14:28

Re: Property als Array
 
Des Weiteren hast du bei einer Property die Möglichkeit zu überprüfen, ob der zugewiesene Wert auch in dein "Konzept" passt.

Soll heißen:
Wenn deine Strings so aufgebaut werden müssen, dass der String IMMER mit "XYZ" beginnt, dann kannst du mit einer Array-Property da schon eingreifen und dir evtl. viel Schreibarbeit und Zeit bei der Fehlersuche sparen.


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