Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Delphi arbeiten mit tobjectlist (https://www.delphipraxis.net/175957-arbeiten-mit-tobjectlist.html)

blinder007 1. Aug 2013 23:22

arbeiten mit tobjectlist
 
hallo community,
ich habe nun mehrere klassen in einer tobjectlist gespeichert. jetzt will ich die procedure einer bestimmten instanz dieser objektliste aufrufen.
gefunden habe ich bis jetzt
tkiclass(kiobjectlist.last).aufrufaktki; (ist halt schon in mein cod umgeschrieben)
oder mit items[index] arbeiten. letzteres funktioneirt aber wohl nicht bei dem aufruf einer methode - wie stelle ich es also an, dass von instanz nummer 3 eine bestimmte methode aufgerufen wird?
grüße
blinder007

sx2008 2. Aug 2013 02:20

AW: arbeiten mit tobjectlist
 
Wenn du ein Objekt aus einer Objektliste nimmst ist es sinnvoll das Objekt in einer lokalen Zwischenvariablen abzulegen.
Beispiel:
Delphi-Quellcode:
var
  i : Integer;
  tmp_obj : TKiClass;
begin
  for i:= 0 to objlist.Count-1 do
  begin
    tmp_obj := TKiClass(objlist.Items[i]);
    // jetzt kann man mit dem ausgelesenen Objekt arbeiten
    tmp_obj.AddEnergy(100);
    tmp_obj.RepairDamage;
  end;

Uwe Raabe 2. Aug 2013 06:52

AW: arbeiten mit tobjectlist
 
... oder man nimmt gleich die generische TObjectList<T> ...

Der schöne Günther 2. Aug 2013 08:29

AW: arbeiten mit tobjectlist
 
Hätte ich spontan auch gesagt.
  • Man sieht direkt was wirklich drinsteckt
  • Man spart sich das Casten

Zur eigentlichen Frage:
Eigentlich geht es mit einem absoluten Index (z.B. 3) genau so wie du es momentan auch machst:

Deine Methode "aufrufAktki()" rufst du ja folgendermaßen auf dem letzten Objekt in der Liste auf:
Delphi-Quellcode:
TKIClass(kiObjectList.Last()).aufrufAktki()
Wenn du nun das an Position drei haben möchtest, ändert sich ja nur das Last():

Delphi-Quellcode:
TKIClass(kiObjectList.Items[3]).aufrufAktki()
oder, als Alternative:

Delphi-Quellcode:
TKIClass(kiObjectList[3]).aufrufAktki()
Wenn du statt einer einfachen
Delphi-Quellcode:
TObjectList
eine
Delphi-Quellcode:
TObjectList<TKIClass>
nimmst, wird es noch einiges kürzer:

Delphi-Quellcode:
kiObjectList[3].aufrufAktki();

Sir Rufo 2. Aug 2013 08:32

AW: arbeiten mit tobjectlist
 
Das 3. Item hat aber den Index 2 ;)
Index 3 zeigt auf das 4. Item

Der schöne Günther 2. Aug 2013 08:38

AW: arbeiten mit tobjectlist
 
Ist das "dritte Item" nun das an "Position Drei" oder "Position Zwei"? Gibt es kein "nulltes Item" aber eins an "Position Null"? Was wenn man ein Array hat, das im Gegensatz zu einer Liste keine "Position Null" hat? Fragen über Fragen... :gruebel:

DeddyH 2. Aug 2013 08:47

AW: arbeiten mit tobjectlist
 
Listen und dynamische Arrays sind grundsätzlich 0-indiziert, d.h. das erste Item hat den Index 0.

silver-moon-2000 2. Aug 2013 09:17

AW: arbeiten mit tobjectlist
 
Zitat:

Zitat von blinder007 (Beitrag 1223220)
[...]ich habe nun mehrere klassen in einer tobjectlist gespeichert. [...]

Zitat:

Zitat von Uwe Raabe (Beitrag 1223226)
... oder man nimmt gleich die generische TObjectList<T> ...

Eine generische ObjectList fährt aber gegen die Wand, sobald er mehrere Klassen verwalten will.
Dann würde ich, ganz grob, so vorgehen:
Delphi-Quellcode:
if kiObjectList.Items[i] is TKIClass then
  (kiObjectList.Items[i] as TKiClass).DoSomething;
if kiObjectList.Items[i] is TPlayerClass then
  (kiObjectList.Items[i] as TPlayerClass).DoSomethingDifferent;
Wobei ich hier einfach mal den "SoftCast"
Delphi-Quellcode:
as
anstelle des HardCasts verwendet habe

Oder habe ich das Ganze wieder einmal falsch interpretiert und es sind mehrere Instanzen *einer* Klasse gemeint?

uligerhardt 2. Aug 2013 09:23

AW: arbeiten mit tobjectlist
 
Zitat:

Zitat von silver-moon-2000 (Beitrag 1223243)
Dann würde ich, ganz grob, so vorgehen:
Delphi-Quellcode:
if kiObjectList.Items[i] is TKIClass then
  (kiObjectList.Items[i] as TKiClass).DoSomething;
if kiObjectList.Items[i] is TPlayerClass then
  (kiObjectList.Items[i] as TPlayerClass).DoSomethingDifferent;
Wobei ich hier einfach mal den "SoftCast"
Delphi-Quellcode:
as
anstelle des HardCasts verwendet habe

Was aber in genau dem Konstrukt überflüssig ist: Das "is" prüft den Typ ja schon, da musst du nicht mit "as" nochmal prüfen.

silver-moon-2000 2. Aug 2013 09:39

AW: arbeiten mit tobjectlist
 
Zitat:

Zitat von uligerhardt (Beitrag 1223245)
Zitat:

Zitat von silver-moon-2000 (Beitrag 1223243)
Wobei ich hier einfach mal den "SoftCast"
Delphi-Quellcode:
as
anstelle des HardCasts verwendet habe

Was aber in genau dem Konstrukt überflüssig ist: Das "is" prüft den Typ ja schon, da musst du nicht mit "as" nochmal prüfen.

Da hast Du auch wieder Recht, aber ich wollte einfach mal zeigen, dass es außer dem harten Cast noch etwas anderes gibt (ja, ich denke, das wird als Ausrede funktionieren...)

Der schöne Günther 2. Aug 2013 10:11

AW: arbeiten mit tobjectlist
 
Aber warum sollte man überhaupt Instanzen mehrerer vollkommen verschiedener Klassen in eine einzige Liste packen wollen?

Auch stehe ich jetzt schon auf dem Schlauch, warum man sich den "as"-Cast sparen können soll? Was, wenn "DoSomethingDifferent" eben erst in der "TPlayerClass" deklariert worden ist?

DeddyH 2. Aug 2013 10:16

AW: arbeiten mit tobjectlist
 
Nicht das "as" sparen, sondern das "is", wenn man sowieso schon "as" verwendet. Da "as" die "is"-Prüfung intern vornimmt, ist die Verwendung beider zusammen doppelt gemoppelt.

uligerhardt 2. Aug 2013 10:19

AW: arbeiten mit tobjectlist
 
Zitat:

Zitat von Der schöne Günther (Beitrag 1223260)
Auch stehe ich jetzt schon auf dem Schlauch, warum man sich den "as"-Cast sparen können soll? Was, wenn "DoSomethingDifferent" eben erst in der "TPlayerClass" deklariert worden ist?

Einen harten Cast nehmen:
Delphi-Quellcode:
if kiObjectList.Items[i] is TPlayerClass then
 TPlayerClass(kiObjectList.Items[i]).DoSomethingDifferent;
Der ist durch das if-is abgesichert.

uligerhardt 2. Aug 2013 10:21

AW: arbeiten mit tobjectlist
 
Zitat:

Zitat von DeddyH (Beitrag 1223261)
Da "as" die "is"-Prüfung intern vornimmt, ist die Verwendung beider zusammen doppelt gemoppelt.

Das ist richtig...

Zitat:

Zitat von DeddyH (Beitrag 1223261)
Nicht das "as" sparen, sondern das "is", wenn man sowieso schon "as" verwendet.

... aber wie willst du dann rausfinden, welche Klasse du gerade behandelst? Doch hoffentlich nicht EBadCast (oder wieauchimmer das Ding heißt) abfangen?

DeddyH 2. Aug 2013 10:25

AW: arbeiten mit tobjectlist
 
Du musst den letzten Nebensatz beachten.

Uwe Raabe 2. Aug 2013 11:31

AW: arbeiten mit tobjectlist
 
Zitat:

Zitat von silver-moon-2000 (Beitrag 1223243)
Eine generische ObjectList fährt aber gegen die Wand, sobald er mehrere Klassen verwalten will.

Nicht mehr als eine nicht-generische TObjectList.

Wenn er wirklich unterschiedliche Klassen verwalten will, die als einzigen gemeinsamen Nachfahren TObject haben, dann ist TObjectList eine Wahl. In allen anderen Fällen bietet sich eine generische Liste über den BasisTyp an. Werden dann wirklich die einzelnen Klasseninstanzen gebraucht, ist eine Phalanx von
Delphi-Quellcode:
if kiObjectList.Items[i] is <SomeClass> then
auch nicht wirklich elegant. Dafür gibt es besser geeignete Patterns (z.B. Visitor).

Ich habe aber trotz der Original-Formulierung
Zitat:

ich habe nun mehrere klassen in einer tobjectlist gespeichert.
das so interpretiert, daß damit mehrere Instanzen einer Klasse gemeint sind.

blinder007 2. Aug 2013 12:52

AW: arbeiten mit tobjectlist
 
hallo,
und ja, ich meinte mehrere instanzen ein und der selben klasse - für jede ki, die in diesem spiel auf tauchen soll eine instanz der klasse tkiclass. diese zahlreichen beiträge helfen mir schon sehr gut weiter und nebenbei habe ich noch was über is und as gelernt :)
dank euch - nur zum schluss: sind die generischen tobjectlisten auch schon in delphi 6 implementiert?
grüße blinder007
edit: dann habe ich es also richtig verstanden, dass ich am besten alle instanzen in lokale objekte lade, dann damit arbeite und sie am ende wieder freigebe?
wenn das so ist, wie kann ich denn dan die änderung eines feldes in speichern. ich habe z.b. das feld fkiposition: tpointer; wie kann ich denn dann die lokale modifizierung dieses feldes wieder in der, aus ihrer ursprünglichen instanz, wieder dort speichern?

DeddyH 2. Aug 2013 12:55

AW: arbeiten mit tobjectlist
 
Generics und damit auch generische Listen gibt es erst ab Delphi 2009.

OlafSt 2. Aug 2013 13:42

AW: arbeiten mit tobjectlist
 
Noch ein Tip zur Güte: Benutze Groß- und Kleinschreibung. Gewöhn dich am besten gleich jetzt daran.

Zum einen ist das in einem Forum guter Ton, denn etliche Leute sehen so einen "allesinkleinundohnekommaundpunkt"-Posts nur kurz an und übergehen ihn dann. Es ist echt mühsam, so ein Konglomerat aus Zeichen zu entziffern. Gib dir gefälligst Mühe, deine Frage lesbar und verständlich zu formulieren - du erwartest schließlich von uns, das wir uns gefälligst dieselbe Mühe geben, dich in die richtige Richtung zu schubsen und dir bei der Problemlösung zu helfen :-D

Das gilt auch für Quelltexte. Die sind enorm viel lesbarer, wenn man sich an die Groß-Kleinschrift-Konventionen hält. Das mag in einem 30-Zeiler, wie du sie z.Zt. noch produzierst, gehen. Wenn es mal 30k oder 300k Zeilen sind (geht wesentlich schneller als man denkt), sieht das anders aus. Besonders, wenn man selbst (oder noch schlimmer: Ein Kollege) nach 6 Monaten einen Bug suchen muß ;)

Ich meins nich böse, also nix für ungut :thumb:

blinder007 2. Aug 2013 14:38

AW: arbeiten mit tobjectlist
 
Zum Schluss dann jetzt noch eine Frage.
Angenommen ich habe eine Instanz aus meiner TObjectlist bestimmt und es in ein lokales Objekt geladen. Nun hat diese Instanz auch Felder, die ich nun lokal auch verändere. Diese Änderungen will ich nun der Ursprungsinstanz wieder zuführen. Reicht dort eine einfache Zuweisung und dann das freigeben des lokalen objekts oder führt das zu fehlern?
grüße
blinder007

Uwe Raabe 2. Aug 2013 14:48

AW: arbeiten mit tobjectlist
 
Zitat:

Zitat von blinder007 (Beitrag 1223305)
Angenommen ich habe eine Instanz aus meiner TObjectlist bestimmt und es in ein lokales Objekt geladen. Nun hat diese Instanz auch Felder, die ich nun lokal auch verändere. Diese Änderungen will ich nun der Ursprungsinstanz wieder zuführen. Reicht dort eine einfache Zuweisung und dann das freigeben des lokalen objekts oder führt das zu fehlern?

Da es sich um eine Klassen-Instanz handelt, arbeitest du immer mit derselben Instanz - ob lokal oder in der Liste. Klassen-Instanzen sind eigentlich Zeiger.

blinder007 2. Aug 2013 15:24

AW: arbeiten mit tobjectlist
 
das bedeutet also, das erzeugen eines lokalen Objekts und die zuweisung bedeutet nur eine einfachere bedienbarkeit? sobald ich aber etwas an den gespeicherten Informationen verändere, ist es egal, von wo aus ich darauf zugreife oder sie verändere?
wenn ich also die lokale instanz erzeugt habe, jetzt den wert eines feldes verändere, die lokale instanz freigebe, hat sich der wert im speicher verändert und ich greife auch auf diesen veränderten Wert zurück, wenn ich ihn abfrage.
ist das richtig verstanden? :)

DeddyH 2. Aug 2013 15:31

AW: arbeiten mit tobjectlist
 
Erzeugst Du eine lokale Instanz, oder weist Du lediglich die bereits vorhandene aus der Liste einer lokalen Variablen zu?

Uwe Raabe 2. Aug 2013 15:37

AW: arbeiten mit tobjectlist
 
Zitat:

Zitat von blinder007 (Beitrag 1223308)
wenn ich also die lokale instanz erzeugt habe, jetzt den wert eines feldes verändere, die lokale instanz freigebe,

Du darfst für die lokale Variable keine eigene Instanz erzeugen, sondern du weist ihr die Instanz aus der TObjectList zu. Dann kannst du die Feldwerte ändern. Auf keinen Fall darfst du die lokale Variable freigeben, da dann der Zeiger auf diese Instanz in der TObjectList ja ungültig würde.

Der schöne Günther 2. Aug 2013 15:40

AW: arbeiten mit tobjectlist
 
Das "Zwischenspeichern" des Verweises auf dein Objekt in der Liste bedeutet nicht nur Vereinfachung/Bequemlichkeit, sondern auch Performance.

Stell dir vor, du willst fünf Dinge mit deinem gesuchten Objekt tun. Würdest du (z.B. mittels Index 3) fünf mal das Objekt in der Liste "suchen" vergeht deutlich mehr Zeit als es einmal zu suchen, sich dann aufzuschreiben, wo es ist und dann die fünf Dinge zu tun.

OlafSt 2. Aug 2013 18:29

AW: arbeiten mit tobjectlist
 
Ich glaube, hier hat jemand das Zeiger-Problem, das schon so unendlich viele Programmierer in den Wahnsinn getrieben hat.

Folgender Code
Delphi-Quellcode:
TMO:=TMyObject.Create;
weist eigentlich den Compiler an, sich ein Stück speicher zu holen (zu reservieren). Das Stück Speicher ist groß genug, das alle Felder und Methoden in diese Stück hineinpassen. Nehmen wir an, der Speicherblock hat die Adresse $00001234.

In der Variablen TMO wird nun nur dieses $00001234 gespeichert.

Nun stopfst du das frisch erzeugte TMO in eine TObjectList. TObjectList wiederum vermerkt in seiner Liste an gespeicherten Objekten nicht das Objekt selbst, sondern eben nur dieses $00001234. Holst du das Objekt aus der TObjectList wieder heraus (z.B. mit
Delphi-Quellcode:
TMO2:=TObjectList[i] as TMyObject
) dann landet in TMO2 auch wieder nur das $00001234.

Da nun zwei Variablen (TMO und TMO2) auf denselben Speicherbereich zeigen (Instanzvariablen sind tatsächlich nix anderes als Zeiger !) ist eine Änderung der Felder in TMO2 auch sofort in TMO zu sehen. Sind ja im Endeffekt beides dieselben Speicherbereiche, ergo die gleichen Instanzen.


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