![]() |
TList und record: Auf Variablen zugreifen
Hallo,
habe folgenden Code:
Delphi-Quellcode:
Nun ist es möglich, dass ich z.B. folgendes machen kann:
TFeedItem = record
Title, Description, Author, URL : String; DateTime : TDateTime; end; TFeedItemClass = class(TPersistent) private fItems: TList; function GetItem(Index: Integer): TFeedItem; procedure SetItem(Index: Integer; const FeedItem: TFeedItem); function GetCount: Integer; public constructor Create; destructor Destroy; override; procedure AddItem(const FeedItem: TFeedItem); procedure RemoveItem(Index: Integer); procedure Clear; property Items[Index: Integer]: TFeedItem read GetItem write SetItem; property Count: Integer read GetCount; end; function TFeedItemClass.GetItem(Index: Integer): TFeedItem; begin Result := TFeedItem(fItems[Index]^); end; procedure TFeedItemClass.SetItem(Index: Integer; const FeedItem: TFeedItem); begin fItems[Index] := @FeedItem; end;
Delphi-Quellcode:
Damit würde das 5. Item mit den neuen Daten überschrieben werden. (In diesem Beispiel existiert das 5. Item natürlich!)
var
Item: TFeedItem; begin Item.Title := 'sdfsdf'; FeedItemClass.Items[5] := Item; end; Es ist aber nicht möglich folgendes zu machen:
Delphi-Quellcode:
Da meckert der Compiler, dass auf Title nur lesend zugegriffen werden kann.
FeedItemClass.Items[5].Title := 'sdfsdfs';
Wo muss ich nun was anpassen, damit ich normal auf die Variablen zugreifen kann? Gruß Sascha |
Re: TList und record: Auf Variablen zugreifen
Du solltest nie "records" als Properties verwenden. durch die interne Speicherverwaltung wird nämlich nie auf die eigentlichen Speicherbereiche verwiesen, sondern nur auf Kopien.
Daher empfehel ich dir die Struktur "TFeedItem" in eine Klasse umzuwandeln & in der Klasse "TFeedItemClass" statt "TList" "TObjectList" zu verwenden. "TObjectList" verwaltet Objekte - sprich gibt deren Speicherbereiche auch korrekt wieder frei. |
Re: TList und record: Auf Variablen zugreifen
Hallo Sascha,
die korrekte Art des Zugriffs hast du selbst schon gezeigt. Das Problem beim direkten Setzen von Title ist die Tatsache, dass du gar nicht auf einen record zugreifst, sondern auf eine function - nur die Notation .Items[5]. gaukelt dir den Zugriff auf eine Struktur TFeedItem vor.
Delphi-Quellcode:
Grüße vom marabu
var
// ... FeedItem: TFeedItem; begin // ... FeedItem := FeedItemClass.Items[5]; FeedItem.Title := 'sdfsdfs'; end; |
Re: TList und record: Auf Variablen zugreifen
Danke ;)
Ich habe es nun aus TFeedItem eine Klasse gebaut und nun klappt es auch alles einwandfrei :) Nur das erste Beispiel funktioniert nur noch teilweise, was auch logisch ist:
Delphi-Quellcode:
Das klappt nun. Muss ich aber nun nicht selbst noch Item wieder freigeben, oder wird das später automatisch gemacht? Denn wenn ich am Ende des Codes Item.Free mache, dann ist es auch unter Items[] nicht mehr drin bzw. nur noch leere Strings. Reicht es aus, wenn ich in der SetItem-Methode eine neue Klasse erzeuge und das übermittelte Item dort übergebe, sodass ich es außerhalb auch ohne Probleme freigeben kann?
var
Item: TFeedItem; begin Item := TFeedItem.Create; Item.Title := 'sdfsdf'; FeedItemClass.Items[5] := Item; end; edit: ok, es reicht nicht aus bzw. klappt so auch nicht... |
Re: TList und record: Auf Variablen zugreifen
Hallo,
ich hatte mir das damals einfacher gemacht, indem ich eine eigene Listen-Klasse (TListEx) und eine Basisklasse für alle Einträge dieser Liste gebaut habe (TListItemEx). Im destructor der TListEx steht dann
Delphi-Quellcode:
Alle Klassen werden von TListItemEx abgeleitet.
{ Listenelemente freigeben }
destructor TListEx.Destroy; begin try ClearList; inherited Destroy; except end; end; { TListEx.Destroy } procedure TListEx.ClearList; var iItem : Integer; Item : TListItemEx; begin try for iItem:= Count-1 downto 0 do begin Item:= Items[iItem]; Delete(iItem); { free, if we have the original pointer here } if (bHasLinks=False) then begin FreeAndNIL(Item); end; end except end; end; #edit# FreeAndNil kann auch durch Item.Free ersetzte werden. Der Destructor ist in Wirklichkeit aber etwas länger, ich benutze das NIL. Das bHasLinks ist ien property, was wenn es True ist, die Klasse selber nicht freigibt, sondern nur aus der Liste löscht. Heiko |
Re: TList und record: Auf Variablen zugreifen
Wie bereits geschrieben verwaltet TObjectList die enthaltenen Objekte. D.h., dass sie beim Freigeben alle enthaltenen Objekte mit freigibt. Du brauchat (und darfst) die Objekte vom Typ "TFeedItem" NICHT selbst freigeben (wenn sie einmal in der TObjectList enthalten sind).
Die Methode von oben würde wie folgt aussehen:
Delphi-Quellcode:
Außerdem würde ich die Methode "SetItem" entfernen, da Du dir mit soetwas evt. die Zeiger auf ein bereits vorhandenes Objekt überschreibst. Dessen Speicherbereich ist dann "vergessen" und vor allem: verloren.
var
Item: TFeedItem; begin Item := TFeedItem.Create; Item.Title := 'sdfsdf'; FeedItemClass.AddItem(Item); end; Die Methode "GetItem" sieht natürlich so aus:
Delphi-Quellcode:
function TFeedItemClass.GetItem(Index: Integer): TFeedItem;
begin Result := FItems[Index] as TFeedItem; end; |
Re: TList und record: Auf Variablen zugreifen
Hallo!
Ich habe hier das Problem, das ich einerseits in der Compare_ Funktion eine EInvalidOp Exception erhalte, andererseits auch noch eine EInvalidOp
Delphi-Quellcode:
Ich habe mich hier mal drangemacht, das Rucksackproblem zu lösen, das ein anderes Mitglied der DP hier erfragt hatte als ich vor einigen Tagen seit langem mal wieder hier vorbeigeschaut habe. Die Procedure Optimize hat folgende Parameter:
type
PObjStruct = ^TObjStruct; TObjStruct = record useability,mass,optimum: Extended; end; TObjects = class(TList) function Add(Item: Pointer): Integer; end; function TObjects.Add(Item: Pointer): Integer; begin PObjStruct(Item).optimum := PObjStruct(Item)^.useability / PObjStruct(Item)^.mass; Result := inherited Add(PObjStruct(Item)); end; function Compare_(Item1,Item2: Pointer): Integer; begin if PObjStruct(Item1)^.optimum < PObjStruct(Item2)^.optimum then Result := -1 else if PObjStruct(Item1)^.optimum > PObjStruct(Item2)^.optimum then Result := +1 else //EInvalidOp in der zweiten Vergleichsoperation Result := 0; end; procedure Optimize(var AObjects,AList: TList; AMaxMass: Extended); var i,j: Integer; amass: Extended; begin amass := 0.0; AList.Sort(Compare_); i := AList.Count-1; while i > 0 do begin amass := amass + PObjStruct(AList.Items[i])^.mass; //EInvalidOp if amass<=AMaxMass then AObjects.Add(PObjStruct(AList.Items[i])) else begin j:=i; while (amass>AMaxMass) and (j>0) do begin amass := amass - PObjStruct(AList.Items[j])^.mass; amass := amass + PObjStruct(AList.Items[j-1])^.mass; if amass<=AMaxMass then AObjects.Add(PObjStruct(AList.Items[j-1])); Dec(j); end; end; Dec(i); end; end; AObjects: Die fertige Liste mit den Objekten, die die Gewichtsschranke einhalten AList: Die Liste mit den Objekten, aus denen passende ausgewählt werden AMaxMass: Die Gewwichtsschranke Leider hänge ich nun fest am Probelem des Zugriffs auf die Recordvariablen in der liste. Wer kann mir hier helfen? Sobald das Problem gelöst ist, soll die Optimize-Prozedur hier in die CodeLibrary aufgenommen werden. schöni |
Re: TList und record: Auf Variablen zugreifen
Habe in der Optimize Prozedur die Listentypen auf TObjects gesetzt. Nun Klappt's.
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 00:41 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