Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   TList 10.1 Berlin vs 10.3 Rio (https://www.delphipraxis.net/205251-tlist-10-1-berlin-vs-10-3-rio.html)

Int3g3r 18. Aug 2020 10:42

Delphi-Version: 10.3 Rio

TList 10.1 Berlin vs 10.3 Rio
 
Guten Tag,

Ich verwende unter Delphi 10.3 Rio folgende routine:

Delphi-Quellcode:
procedure Tfrm_Umsatz_Statistik.GUIUmsatzMitKunde(_visible: boolean);
var elements : TList;
      ele : TObject;
begin
   elements := Tlist.Create;
   elements.Add(Label3);
   elements.Add(lblDatumUnbestimmt);
   elements.Add(ChkBoxDatumsbereich);
   elements.Add(chkBoxGattungSelect);
   elements.Add(lblTitelGattung);
   elements.Add(ChkBoxAlleGattung);
   elements.Add(Label7);


   for ele in elements do
   begin
       if ele is TLabel then
       begin
            Tlabel(ele).Visible := _visible;
       end
       else if ele is TCheckBox then
       begin
            TCheckBox(ele).Visible := _visible;
       else if ele is TListBox then
       begin
            TListBox(ele).Visible := _visible;
       end;
   end;
   elements.Free;
end;
Lässt sich unter 10.3 Rio ohne weiteres compillieren.

Unter 10.1 erhalte ich folgende Fehlermeldung:
Zitat:

[dcc32 Fehler] form_Umsatz_Statistik.pas(1412): E2010 Inkompatible Typen: 'TObject' und 'Pointer'
Die Fehlermeldung ist bezogen auf die for-in-Schleife.

Wie lässt sich diese procedure in 10.1 verwenden ?

Ich habe es versucht mit Pointern wie folgt zu realisieren :
Delphi-Quellcode:
procedure Tfrm_Umsatz_Statistik.GUIUmsatzMitKunde(_visible: boolean);
var elements : TList;
      ele : ^TObject;
begin
   elements := Tlist.Create;
   elements.Add(Label3);
   elements.Add(lblDatumUnbestimmt);
   elements.Add(ChkBoxDatumsbereich);
   elements.Add(chkBoxGattungSelect);
   elements.Add(lblTitelGattung);
   elements.Add(ChkBoxAlleGattung);
   elements.Add(Label7);


   for ele in elements do
   begin
       if ele^ is TLabel then
       begin
            Tlabel(ele^).Visible := _visible;
       end
       else if ele^ is TCheckBox then
       begin
            TCheckBox(ele^).Visible := _visible;
       else if ele^ is TListBox then
       begin
            TListBox(ele^).Visible := _visible;
       end;
   end;
   elements.Free;
end;
Hier erhalte ich eine access-violation beim dereferenzieren zur Laufzeit. An der Stelle
Delphi-Quellcode:
if ele^ is TLabel then


Gruss Int3g3r

TiGü 18. Aug 2020 10:55

AW: TList 10.1 Berlin vs 10.3 Rio
 
Mach doch ne generische
Delphi-Quellcode:
elements : TList<TControl>;
draus;

Delphi-Quellcode:
procedure Tfrm_Umsatz_Statistik.GUIUmsatzMitKunde(_visible: boolean);
var
  Controls: TList<TControl>;
  Control: TControl;
begin
  Controls := TList<TControl>.Create;
  try
    Controls.Add(Label3);
    Controls.Add(lblDatumUnbestimmt);
    Controls.Add(ChkBoxDatumsbereich);
    Controls.Add(chkBoxGattungSelect);
    Controls.Add(lblTitelGattung);
    Controls.Add(ChkBoxAlleGattung);
    Controls.Add(Label7);

    for Control in Controls do
    begin
        Control.Visible := _visible
    end;
  finally
    Controls.Free;
  end;
end;

UliBru 18. Aug 2020 11:18

AW: TList 10.1 Berlin vs 10.3 Rio
 
What about
Delphi-Quellcode:
procedure TTestForm.Button1Click(Sender: TObject);
var
  elements: TList;
  i: integer;
begin
  elements := TList.Create;
  try
    elements.Add(Label1);
    for i := 0 to elements.Count - 1 do
    begin
      if TObject(elements.Items[i]) is TLabel then
        TLabel(elements.Items[i]).Visible := true;
    end;
  finally
    elements.Free;
  end;
end;
?

Grüsse
Uli

Int3g3r 18. Aug 2020 11:32

AW: TList 10.1 Berlin vs 10.3 Rio
 
Vielen Dank für die Lösungsvorschläge.
Die Generische Liste zu verwenden ist wohl die einfachste Lösung.

Trotzdem möchte ich wissen warum ich eine access-violation erhalte im Beispiel mit dem Pointer oben.
Solche Fehlermeldungen sind für mich sehr schwierig nachvollziebar.

Delphi-Quellcode:
if ele^ is TLabel then
ist doch fast das gleiche wie
Delphi-Quellcode:
TObject(elements.Items[i]) is TLabel then
?!
Darum habe ich oben auch ein typisierten-^TObject-Pointer genommen, somit wird beim dereferenzieren der Wert/Objekt in ein TObject gecastet.

Gruss Int3g3r

UliBru 18. Aug 2020 11:37

AW: TList 10.1 Berlin vs 10.3 Rio
 
Ich hab noch mal weitergespielt:
Delphi-Quellcode:
procedure TTestForm.Button1Click(Sender: TObject);
var
  elements: TList;
  ele: Pointer;
begin
  elements := TList.Create;
  try
    elements.Add(Label1);
    for ele in elements do
    begin
      if TObject(ele) is TLabel then
        TLabel(ele).Visible := true;
    end;
  finally
    elements.Free;
  end;
end;
TList enhält eine Liste von Pointern. Mit ele vom Typ Pointer klappts denn auch.

Grüsse
Uli

Int3g3r 18. Aug 2020 12:17

AW: TList 10.1 Berlin vs 10.3 Rio
 
Zitat:

Zitat von UliBru (Beitrag 1472000)
Ich hab noch mal weitergespielt:
TList enhält eine Liste von Pointern. Mit ele vom Typ Pointer klappts denn auch.
Grüsse
Uli

Danke Uli!
Warum muss man bei
Delphi-Quellcode:
TObject(ele)
nicht dereferenzieren ?
Ich möchte ja das Objekt an der Adresse "ele" casten und nicht die Adresse selbst.:shock:
TObject(ele) lese ich so das die Adresse "ele" in ein TObject gecastet wird, dies sollte aber nicht möglich sein.

Gruss Int3g3r

Bernhard Geyer 18. Aug 2020 12:43

AW: TList 10.1 Berlin vs 10.3 Rio
 
Wieso nicht das?

https://www.delphipraxis.net/1471996-post2.html

himitsu 18. Aug 2020 13:17

AW: TList 10.1 Berlin vs 10.3 Rio
 
Du hast eine TList mit Pointern, also muß ele ein Pointer sein.
Delphi-Quellcode:
var ele: Pointer;

for ele in elements do
  if TObject(ele) is ... then
Man kann sowas versuchen, aber leider mag der Compiler das oft nicht. "... muß eine Variable sein, bla bla bla"
Delphi-Quellcode:
var ele: TObject;

for Pointer(ele) in elements do
Oder man ist mal etwas böse.
Delphi-Quellcode:
var
  _ele: Pointer;
  ele: TObject absolute _ele;

for _ele in elements do
  if ele is ... then

Wieso keine TObjektList oder gar eine generische TList<TObject> (oder TComponent/TMyIrgendwas/...) ?



Und ja, da hier überall VISIBLE vorkommt, ist es eigentlich nötig sich den gemeinsamen Vorfahren rauszusuchen und dann das nur einmal zu machen.
Da Visible aber in der Basis protected ist, und man hier weiß, dass ALLEs ein Visible (das Selbe) hat, kann man hier auch blind in einen Typen casten, wo es public ist ... siehe UliBru.

Delphi-Quellcode:
procedure TTestForm.Button1Click(Sender: TObject);
var ele: Pointer;

for ele in elements do
  if TObject(ele) is TControl then
    TLabel(ele).Visible := true;

Rollo62 18. Aug 2020 13:47

AW: TList 10.1 Berlin vs 10.3 Rio
 
Zitat:

Zitat von himitsu (Beitrag 1472007)

Oder man ist mal etwas böse.
Delphi-Quellcode:
var
  _ele: Pointer;
  ele: TObject absolute _ele;

for _ele in elements do
  if ele is ... then

Wieso böse, ist das kein valider Code ?
Ich denke das ist gensu für sowas erfunden worden :stupid:

Int3g3r 18. Aug 2020 13:49

AW: TList 10.1 Berlin vs 10.3 Rio
 
Zitat:

Zitat von himitsu (Beitrag 1472007)
Wieso keine TObjektList oder gar eine generische TList<TObject> (oder TComponent/TMyIrgendwas/...) ?

Was bietet mir eine TObjectList im gegensatz zu einer TList ?
Bei einer TObjectList ist es noch notwendig eine unit einzubinden.
Den Namen dieser unit vergesse ich sehr schnell daher ist es für mich einfacher mit einer TList zu arbeiten.
In meinem Fall ist es doch nicht notwenig eine TObjectList zu benutzen, eine TList reicht komplett aus für mein vorhaben.
Dazu kommt das eine TObjectList auch einen Pointer erwartet.

Somit ist dann eine generische TList<> die bessere Wahl.

Mir geht es aber darum etwas zu lernen. Damit ich mir bei solchen Problemen selbst helfen könnte.
Daher möchte ich auch wissen warum das obere Beispiel mit dem Pointer nicht funktioniert.
Delphi-Quellcode:
ele : ^TObject
ist auch ein Pointer.
Warum muss beim casten von TObject(ele) der Pointer nicht dereferenziert werden ?
Warum erhalte ich bei meinem Beispiel(mit Pointer) oben eine access-violation exception ?

Gruss Int3g3r

TiGü 18. Aug 2020 13:50

AW: TList 10.1 Berlin vs 10.3 Rio
 
Zitat:

Zitat von himitsu (Beitrag 1472007)
Wieso keine TObjektList oder gar eine generische TList<TObject> (oder TComponent/TMyIrgendwas/...) ?

Und ja, da hier überall VISIBLE vorkommt, ist es eigentlich nötig sich den gemeinsamen Vorfahren rauszusuchen und dann das nur einmal zu machen.

Liest du eigentlich noch die anderen Beiträge oder versuchst du auf Teufel komm raus auf 40.000 Beiträge zu kommen?

Zitat:

Zitat von himitsu (Beitrag 1472007)
Da Visible aber in der Basis protected ist, und man hier weiß, dass ALLEs ein Visible (das Selbe) hat, kann man hier auch blind in einen Typen casten, wo es public ist ... siehe UliBru.

Das ist sachlich falsch. Die Eigenschaft TControl.Visible ist public.

himitsu 18. Aug 2020 14:15

AW: TList 10.1 Berlin vs 10.3 Rio
 
Einiges fehlte noch und den Rest zusammenfassend mit aufgeführt.

Zitat:

Zitat von Int3g3r (Beitrag 1472002)
Ich möchte ja das Objekt an der Adresse "ele" casten und nicht die Adresse selbst.:shock:

Du hast reinzu auch direkt TObject-Nachfahren nach Pointer (implizit) gecastet,
also muß es rückzu genauso sein, also Pointer nach TObjekt aka
Delphi-Quellcode:
TObject(ele)
.

Zitat:

Zitat von Int3g3r (Beitrag 1472010)
Was bietet mir eine TObjectList im gegensatz zu einer TList ?

Weil es bereits einen passenderen Typen besitzt und man nicht erst böse casten muß?
Objekte rein, Objekte raus und das alles inklusive einer funktionierenden Typprüfung.

Bei Pointer mußt du ja harte Casts benutzen, womit die Typ-Prüfung des Compilers umgangen wird.

Da Einzige, was der Compiler prüfen kann, ist dass sie zumindestens die gleiche Größe haben, aber ob in ele wiklich "Objekte" drin ist, kann nicht geprüft werden.
Falls das nicht stimmt, kann der Code extrem schöne Fehler produzieren, welches nicht passieren würde, hätte man die Typprüfung des Compilers auf seiner Seite.

Mit TList<TControl> sogar noch sicherer, da man hier gleich weiß, dass in der Liste nur Objekte sein können, welche die Visible-API enthalten.
(gut, es kann sein, dass hier Visible nicht verwendet wird, aber dennoch lässt es sich auffrufen und macht dann einfach nichts ... aber es knallt wenigstens nicht)


Implizit:
TObjekt nach Pointer geht, da ein Objektzeiger (Variable oder Parameter) "zufällig" genauso groß wie ein Pointer ist, weil er "intern" einen Zeiger enthält, drum besitzt Delphi hier einen impliziten Cast (weil sowas oft von Entwicklern gemacht wird),
aber andersrum geht es nicht, da ein Pointer nicht immer ein Objekt-Zeiger sein muß und es sich auch nicht 100% sicher prüfen lässt, ob es so ist.


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