AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Object-Pascal / Delphi-Language Anzeigen wenn sich in TObjectList ein Eintrag geändert hat
Thema durchsuchen
Ansicht
Themen-Optionen

Anzeigen wenn sich in TObjectList ein Eintrag geändert hat

Ein Thema von norwegen60 · begonnen am 3. Apr 2021 · letzter Beitrag vom 5. Apr 2021
Antwort Antwort
Benutzerbild von dummzeuch
dummzeuch

Registriert seit: 11. Aug 2012
Ort: Essen
1.698 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#1

AW: Anzeigen wenn sich in TObjectList ein Eintrag geändert hat

  Alt 3. Apr 2021, 09:08
Delphi-Quellcode:
procedure TBase.SetChanged(const Value: Boolean);
begin
  if FChanged <> Value then
  begin
    FChanged := Value;
    if (FParentObject is TBaseObjectList) then // Prüfen, ob der Parent des Wertes eine TBaseObjectList ist
      TBaseObjectList(FParentObject).Changed := true; // Und wenn ja, die Liste auch auf Changed setzen
  end;
end;
Ist das korrekt? Müsste es nicht heißen:

Delphi-Quellcode:
procedure TBase.SetChanged(const Value: Boolean);
begin
  if FChanged <> Value then
  begin
    FChanged := Value;
    if Value and <FParentObject is TBaseObjectList) then // <<< Änderung hier
      TBaseObjectList(FParentObject).Changed := true;
  end;
end;
Also nur wenn der neue Wert True ist, auch Changed der Liste auf True setzen?

Kann sein, dass es in Deinem Anwendungsfall keinen Unterschied macht, kommt mir aber falsch vor.

Und wenn ich so den Werte eines Eintrags ändere, steht dieser Wert auf Changed und es sollte auch die Liste auf Changed = True stehen
So weit, so gut. Man kann anhand des Changed Flags der Liste erkennen, ob ein Eintrag in der Liste geändert wurde.

Mir ist nicht ganz klar, was Du damit meinst:

Aktuell gehe ich bei jedem Save-Vorgang durch die verschiedenen Listen, aber es wäre eben resourcenschonender wenn ich gleich an der Liste selber sehen würde, ob ein Wert geändert wurde.

Gibte es eine Möglichkeit das zu realisiseren
Suchst Du nach einer Möglichkeit, neben der reinen Information, dass mindestens ein Eintrag in einer Liste geändert wurde, auch zu sehen, welche Einträge geändert wurden, ohne die Liste durchgehen zu müssen?

Das ginge z.B., indem man zusätzlich noch eine ChangedObjects Liste mit Pointern auf die geänderten Objekte pflegt. Dann braucht man beim Speichern nur die ChangedObjects Liste durchgehen, die Objekte speichern und ChangedObjects löschen.

Folgendes ist dabei zu beachten:
  • Beim Löschen eines Eintrag aus der Hauptliste muss dieser ggf. auch aus der ChangedObjects Liste gelöscht werden.
  • Multithreading würde hier nochmal deutlich komplexer.

Es ginge noch mit etwas geringerem Speicherverbrauch ohne eine ChangedObjects Liste, indem man einen Changed Counter führt und dann beim Abspeichern der Liste die Einträge nur so lange durch geht, bis man genau diese Anzahl Änderungen gefunden und gespeichert hat. Das spart im Durchschnitt etwas Zeit. Wenn man Pech hat, wurde aber der letzet Eintrag geändert und man muss alle Einträge durchgehen, bis man den geänderten gefunden hat. Das kann man nochmal etwas optimieren, indem man den kleinste und den größten Index der geänderten Objekte pflegt, allerdings ist das ziemlich kompliziert, falls auch Einträge hinzugefügt und gelöscht werden, denn dann muessen jeweils auch diese beiden Indexe angepasst werden.
Thomas Mueller

Geändert von dummzeuch ( 3. Apr 2021 um 09:10 Uhr)
  Mit Zitat antworten Zitat
norwegen60

Registriert seit: 23. Dez 2007
Ort: Schwarzwald
526 Beiträge
 
Delphi 12 Athens
 
#2

AW: Anzeigen wenn sich in TObjectList ein Eintrag geändert hat

  Alt 3. Apr 2021, 10:03
Ist das korrekt? Müsste es nicht heißen:

Delphi-Quellcode:
procedure TBase.SetChanged(const Value: Boolean);
begin
  if FChanged <> Value then
  begin
    FChanged := Value;
    if Value and <FParentObject is TBaseObjectList) then // <<< Änderung hier
      TBaseObjectList(FParentObject).Changed := true;
  end;
end;
Ja, da hast du natürlich recht. Das Problem ist aber, dass Delphi die Typprüfung if (FParentObject is TBaseObjectList) then nicht akzeptiert. Genauso wenig wie die Zuweisung TBaseObjectList(FParentObject).Changed := true . Und da suche ich nach einer Möglichkeit, wie ich auf die BasisListe per TypeCast zugreifen kann.

Das mit dem Counter oder der zusätzlichen Liste sind Möglichkeiten, machen die Listenverwaltung aber nicht einfacher.
In meiner Anwendung gibt es 61 TObjectList und von der ein oder anderen noch mehrere Instanzen.
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.688 Beiträge
 
Delphi 12 Athens
 
#3

AW: Anzeigen wenn sich in TObjectList ein Eintrag geändert hat

  Alt 3. Apr 2021, 10:13
Versuch's mal so:
Delphi-Quellcode:
    if (FParentObject is TBaseObjectList<TBase>) then
      TBaseObjectList<TBase>(FParentObject).Changed := true;
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.688 Beiträge
 
Delphi 12 Athens
 
#4

AW: Anzeigen wenn sich in TObjectList ein Eintrag geändert hat

  Alt 3. Apr 2021, 10:16
Konsequenterweise sollte man die Liste auch so deklarieren: TBaseObjectList<T: TBase>
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
norwegen60

Registriert seit: 23. Dez 2007
Ort: Schwarzwald
526 Beiträge
 
Delphi 12 Athens
 
#5

AW: Anzeigen wenn sich in TObjectList ein Eintrag geändert hat

  Alt 3. Apr 2021, 12:33
Vielen Dank
Mit den Änderungen lässt sich das Testprojekt jetzt compilieren. Aber zwei Dinge treten noch auf
  • Die Abfrage (FParentObject is TBaseObjectList<TBase>) bringt kein TRUE zurück, obwohl ich lNamen.ParentObject := lNamenList; zugewiesen habe
  • Spätestens wenn ich das Programm beende, kommt ein EAccessViolation auf. Kann aber auch schon passieren, wenn ich aus dem Programm in die IDE wechsle.

Ich bin nicht sicher, ob ich den Zusatz richtig verstanden habe
Konsequenterweise sollte man die Liste auch so deklarieren: TBaseObjectList<T: TBase>
Ich habe es auf verschiedene Arten probiert, das Verhalten blieb aber immer gleich
Delphi-Quellcode:
  TBaseObjectList<T: class> = class(TObjectList<T>)
  TBaseObjectList<T: TBase> = class(TObjectList<T>)
  TBaseObjectList<TBase: class> = class(TObjectList<TBase>)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu
Online

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.400 Beiträge
 
Delphi 12 Athens
 
#6

AW: Anzeigen wenn sich in TObjectList ein Eintrag geändert hat

  Alt 3. Apr 2021, 13:38
Problem ist, dass bei den Generics die Vererbung bissl "komisch" arbeitet und die Hierarchie nicht immer so aussieht, wie man denken könnte.


Aber ich hätte auch gedacht, dass es bei diesen 3 Varianten hätte gehen sollen, da du eigentlich auf den gleichen selben Typ prüfst und der ja gleich sein müsste.
Wobei 1 und 3 das Selbe ist, von den Typen her, da sich nur der Bezeichner unterscheidet. (ob es A oder B heißt, macht keinen Unterschied)
[EDIT] Das TBase in is ...<TXyz> war doch das TXyz aus TBaseObjectList<TXyz: class> = ... und nicht das "einzelne" TBase = class ?

Aber bei TBaseObjectList<T: TBase> = class(... ist diese Prüfung auch nicht nötig, da bereits der Compiler die Prüfung übernimmt und du somit einfach "blind" hart casten kannst, weil es nichts Anderes sein kann.
Ein Therapeut entspricht 1024 Gigapeut.

Geändert von himitsu ( 3. Apr 2021 um 14:36 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.688 Beiträge
 
Delphi 12 Athens
 
#7

AW: Anzeigen wenn sich in TObjectList ein Eintrag geändert hat

  Alt 3. Apr 2021, 16:54
So sollte es auf der sicheren Seite sein:
Delphi-Quellcode:
type
  TBase = class;
  TBaseObjectList = class(TObjectList<TBase>)
  private
    FChanged: Boolean;
  public
    constructor Create(AOwnsObjects: Boolean = True); overload;
    property Changed: Boolean read FChanged write FChanged;
  end;
  TBaseObjectList<T: TBase> = class(TBaseObjectList);
Dann kannst du auch wieder auf TBaseObjectList prüfen und casten:
Delphi-Quellcode:
procedure TBase.SetChanged(const Value: Boolean);
begin
  if FChanged <> Value then begin
    FChanged := Value;
    if (FParentObject is TBaseObjectList) then
      TBaseObjectList(FParentObject).Changed := True;
  end;
end;
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Antwort Antwort


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 15: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