AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Programmieren allgemein Delphi Multi-ObjectLists (Objekte mehrmals in einer Liste)
Thema durchsuchen
Ansicht
Themen-Optionen

Multi-ObjectLists (Objekte mehrmals in einer Liste)

Ein Thema von himitsu · begonnen am 12. Jul 2010 · letzter Beitrag vom 12. Jul 2010
Antwort Antwort
Benutzerbild von himitsu
himitsu

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

Multi-ObjectLists (Objekte mehrmals in einer Liste)

  Alt 12. Jul 2010, 11:23
Nja, was soll man dazu sagen?

Dieses sind einfach nur Listen, in welchen das selbe Objekt mehrmals enthalten sein kann, ohne das es Probleme geben könnte.

> Es gibt nur Auswirkungen, wenn OwnsObjects auf TRUE steht,
> sonst reagieren diese Listen, wie ihre "normalen" Verwandten.

Ist ein Objekt mehrmals vorhanden, dann wird es erst freigegeben, wenn keine Instanzen mehr in der Liste stecken.
(bei den normalen Listen wird das Objekt ja ohne Prüfung sofort freigegeben)

Delphi-Quellcode:
unit MultiLists;

interface
  {$DEFINE UseGenerics}

  uses
    Classes, Contnrs {$IFDEF UseGenerics}, Generics.Collections{$ENDIF};

  type
    TMultiObjectList = class(TObjectList)
    protected
      procedure Notify(Ptr: Pointer; Action: TListNotification); override;
    public
      function Remove(AObject: TObject; RemoveAll: Boolean): Integer; overload;
      procedure RemoveAll(AObject: TObject); inline;
    end;

    TMultiObjectStringList = class(TStringList)
    protected
      procedure PutObject(Index: Integer; AObject: TObject); override;
    public
      destructor Destroy; override;
      procedure Clear; override;
      procedure Delete(Index: Integer); override;
    end;

    {$IFDEF UseGenerics}

      TMultiObjectList<T: class> = class(TObjectList<T>)
      protected
        procedure Notify(const Value: T; Action: TCollectionNotification); override;
      public
        function Remove(const Value: T; RemoveAll: Boolean): Integer; overload;
        procedure RemoveAll(const Value: T); inline;
      end;

    {$ENDIF}

implementation
  procedure TMultiObjectList.Notify(Ptr: Pointer; Action: TListNotification);
  begin
    if (Action = lnDeleted) and OwnsObjects then begin
      if IndexOf(TObject(Ptr)) < 0 then
        TObject(Ptr).Free;
    end else inherited;
  end;

  function TMultiObjectList.Remove(AObject: TObject; RemoveAll: Boolean): Integer;
  var
    i: Integer;
  begin
    if RemoveAll then begin
      Result := -1;
      repeat
        i := Remove(AObject);
        if i >= 0 then Result := i;
      until i < 0;
    end else Result := Remove(AObject);
  end;

  procedure TMultiObjectList.RemoveAll(AObject: TObject);
  begin
    while Remove(AObject) >= 0 do ;
  end;

  procedure TMultiObjectStringList.PutObject(Index: Integer; AObject: TObject);
  var
    Temp: TObject;
    B: Boolean;
    i: Integer;
  begin
    if Assigned(AObject) then begin
      Temp := Objects[Index];
      if Temp <> AObject then begin
        inherited;
        if IndexOf(Temp) < 0 then
          Temp.Free;
      end;
    end else inherited;
  end;

  destructor TMultiObjectStringList.Destroy;
  begin
    OnChange := nil;
    OnChanging := nil;
    Clear;
    inherited;
  end;

  procedure TMultiObjectStringList.Clear;
  var
    i, i2: Integer;
    Temp: Tobject;
  begin
    BeginUpdate;
    try
      if (Count <> 0) and OwnsObjects then
        for i := Count - 1 downto 0 do begin
          Temp := Objects[i];
          for i2 := i - 1 downto 0 do
            if Objects[i2] = Temp then Objects[i2] := nil;
          Objects[i] := nil;
          Temp.Free;
        end;
      inherited;
    finally
      EndUpdate;
    end;
  end;

  procedure TMultiObjectStringList.Delete(Index: Integer);
  var
    Temp: Tobject;
    i: Integer;
  begin
    if OwnsObjects then begin
      BeginUpdate;
      try
        Temp := Objects[Index];
        for i := Count - 1 downto 0 do
          if (i <> Index) and (Objects[i] = Temp) then begin
            Objects[Index] := nil;
            break;
          end;
        inherited;
      finally
        EndUpdate;
      end;
    end else inherited;
  end;

  {$IFDEF UseGenerics}

    procedure TMultiObjectList<T>.Notify(const Value: T; Action: TCollectionNotification);
    var
      B: Boolean;
      i: Integer;
    begin
      if (Action = cnRemoved) and OwnsObjects then begin
        if Assigned(OnNotify) then OnNotify(Self, Value, cnRemoved);
        if IndexOf(Value) < 0 then Value.Free;
      end else inherited;
    end;

    function TMultiObjectList<T>.Remove(const Value: T; RemoveAll: Boolean): Integer;
    var
      i: Integer;
    begin
      if RemoveAll then begin
        Result := -1;
        repeat
          i := Remove(Value);
          if i >= 0 then Result := i;
        until i < 0;
      end else Result := Remove(AObject);
    end;

    procedure TMultiObjectList<T>.RemoveAll(const Value: T);
    begin
      while Remove(Value) >= 0 do ;
    end;

  {$ENDIF}

end.
[edits]
- kleine Optimierungen (einige For-Schleifen gegen IndexOf ersetzt)
- RemoveAll und Co. eingeführt
- RemoveAll-Parameter wird nun auch beachtet
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PoSex im Delphi viel seltener praktiziert.

Geändert von himitsu (12. Jul 2010 um 13:00 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Stevie
Stevie

Registriert seit: 12. Aug 2003
Ort: Soest
4.016 Beiträge
 
Delphi 10.1 Berlin Enterprise
 
#2

AW: Multi-ObjectLists (Objekte mehrmals in einer Liste)

  Alt 12. Jul 2010, 11:40
Zumindest bei der TMultiObjectList<T> musst du noch Remove überschreiben/überladen. Imho müsste über diese Methode jede Referenz aus der Liste gelöscht werden und nicht nur die erste gefundene.
Stefan
“Simplicity, carried to the extreme, becomes elegance.” Jon Franklin

Delphi Sorcery - DSharp - Spring4D - TestInsight
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

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

AW: Multi-ObjectLists (Objekte mehrmals in einer Liste)

  Alt 12. Jul 2010, 11:59
Zumindest bei der TMultiObjectList<T> musst du noch Remove überschreiben/überladen. Imho müsste über diese Methode jede Referenz aus der Liste gelöscht werden und nicht nur die erste gefundene.
Hmmm joar, ist soeine Sache ... eigentlich wollte ich nur das Löschverhalten beeinflussen und nicht den Aufbau der Listen.

Normaler Weise entfernt Remove doch nur den ersten Fund aus der Liste
und nicht alle Vorkommen ... aber die normale (generische) Objektliste gibt dennoch das Objekt frei, selbst wenn es nochmals in der Liste steht.

So jetzt besser?
RemoveAll(Value: T) .
oder wäre ein Remove(Value: T; RemoveAll: Boolean = false) besser?

[edit]
Hab nun Beides verbaut.
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PoSex im Delphi viel seltener praktiziert.

Geändert von himitsu (12. Jul 2010 um 12:06 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Stevie
Stevie

Registriert seit: 12. Aug 2003
Ort: Soest
4.016 Beiträge
 
Delphi 10.1 Berlin Enterprise
 
#4

AW: Multi-ObjectLists (Objekte mehrmals in einer Liste)

  Alt 12. Jul 2010, 12:17
Hab nun Beides verbaut.
Solltest noch den Parameter RemoveAll in der Remove Methode berücksichtigen.

Edit: Evtl wäre es auch sinnig, die Eigenschaft Duplicates vom Typ
TDuplicates = (dupIgnore, dupAccept, dupError); einzubauen (so wie in TStringList z.B.)
Stefan
“Simplicity, carried to the extreme, becomes elegance.” Jon Franklin

Delphi Sorcery - DSharp - Spring4D - TestInsight

Geändert von Stevie (12. Jul 2010 um 12:21 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

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

AW: Multi-ObjectLists (Objekte mehrmals in einer Liste)

  Alt 12. Jul 2010, 12:57
Solltest noch den Parameter RemoveAll in der Remove Methode berücksichtigen.
kümmer mich gleich drum (blödes Copy&Paste)

Edit: Evtl wäre es auch sinnig, die Eigenschaft Duplicates vom Typ
TDuplicates = (dupIgnore, dupAccept, dupError); einzubauen (so wie in TStringList z.B.)
Ich war erst auf die Idee gekommen das OwnerObjects zu verändern, von einem Boolean zu einem Enum, mit mehreren Auswahlmöglichkeiten, aber das ließ sich nachträglich nicht gut ändern.

Wobei, wie schon erwähnt, diese Lieste ja eigentlich mehrere gleiche Objekte enthalten soll/darf, da wäre es doch kontraproduktiv, wenn man dieses jetzt auch noch verhindert/verbietet?
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PoSex im Delphi viel seltener praktiziert.

Geändert von himitsu (12. Jul 2010 um 13:00 Uhr)
  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 05:05 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