Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - prüfen was für eine klasse hinter einem pointer steckt


cbs - Mi 24.09.03 20:07
Titel: prüfen was für eine klasse hinter einem pointer steckt
huhu

ich möchte ein object mit einem TreeNode (von TTreeView) verknüpfen und beim auswählen dieses Nodes einige Daten des Objects verarbeiten/anzeigen.

ich habe dazu in der Data eigenschaft des Nodes mein Object abgelegt (bessergesagt den pointer darauf)

wenn der User auf einen Node klickt möchte ich die Data eigenschaft des selektierten Nodes auslesen und abhängig davon was es für ein Object ist daten anzeigen oder verarbeiten. soll heißen das es verschiedene objecte sein können und ich möchte herrausfinden was es für ein object ist damit ich entsprechend an die daten wieder herran komme

also: wie kann ich prüfen was für eine klasse hinter einem pointer steckt?

ungefähr so stell ich mir das vor (funktioniert natürlich nicht)


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
if Node.Data = TData then begin
  TData(Node.Data).{blabla}
end;

if Node.Data = TDataProject then begin
  TDataProject(Node.Data).{blabla}
end;


ich hab da schon abenteuerliche kombinationen mit is und as probiert. aber habs noch nicht hinbekommen


UC-Chewie - Mi 24.09.03 20:10

Du musst dein = aus dem Vergleich eigentlich nur durch is ersetzen.

Alternativ kannst du einen Cast nach TObject machen und dort die Methode ClassName aufrufen. Da bekommst du den Namen des Typs als String.


cbs - Mi 24.09.03 20:22

jo danke dir UC-Chewie

das mit dem is funtioniert nicht


Delphi-Quelltext
1:
2:
3:
if Node.Data is TData then begin 

end;

Compiler hat folgendes geschrieben:
Operator ist auf diesen Operandentyp nicht anwendbar


aber die sache mit classname hilft mir schon weiter


Delphi-Quelltext
1:
TObject(Node.Data).ClassName                    


schicke sache, aber kann ich das auch direkt prüfen? ohne den umweg mit classname?


Shark - Mi 24.09.03 21:15

wenn Du alles von einer bestimmten Klasse abgeleitet hast, dann funktioniert "is" wie folgt


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
var Object: TUrClass <- Beispiel


Object := Node.Data;
if Object is TClass then
...


einen unbestimmten Pointer kannst Du mit is nicht vergleichen!

Moderiert von user profile iconKlabautermann: Delphi-Tags hinzugefügt.


UC-Chewie - Mi 24.09.03 21:22

Ach so, Data ist ein Pointer.
Dann so:

Delphi-Quelltext
1:
if TObject(Node.Data) is TData then                    



Zitat:
schicke sache, aber kann ich das auch direkt prüfen? ohne den umweg mit classname?


Wieso Umweg?


Shark - Mi 24.09.03 21:28

Man sollte "as" noch ansprechen:


Delphi-Quelltext
1:
2:
3:
4:
5:
Object1 : TUrClass;
Object2 : TClass;

if Object1 is TClass then
  Object2 := Object1 as TClass;


Moderiert von user profile iconKlabautermann: Delphi-Tags hinzugefügt.


cbs - Mi 24.09.03 23:00

ah danke euch beiden :D

Shark hat folgendes geschrieben:
wenn Du alles von einer bestimmten Klasse abgeleitet hast...


Sämtliche klassen haben doch eh TObject als Urklasse oder? also kann ich doch generell mit TObject die Klasse prüfen oder?

also

Delphi-Quelltext
1:
TObject(Node.Data) is TData                    



UC-Chewie hat folgendes geschrieben:
Wieso Umweg?

jo hast recht. die lösung mitclassname ist auch nicht viel schwieriger/komplizierter als direkt mit is zu prüfen

thx nochmal :lol:


datensender - Do 25.09.03 09:12

shark hat folgendes geschrieben:
Man sollte "as" noch ansprechen:
Object1 : TUrClass;
Object2 : TClass;
if Object1 is TClass then
Object2 := Object1 as TClass;


wenn du vorher bereits mit "is" prüfst, wäre ein anschließendes "as" doppelt gemoppelt... ("as" prüft dann nämlich noch einmal auf die Klasse, wobei das Ergebnis dann in diesem Fall immer gültig ist und nie eine Fehlermeldung erzeugt wird/werden kann... andernfalls wäre bereits "is" abgesprungen...)

nach dem Test mit "is" kannst du also auch gleich statisch casten....


cbs - Do 25.09.03 09:27

datensender hat folgendes geschrieben:
nach dem Test mit "is" kannst du also auch gleich statisch casten....


örm...
wenn du das damit meinst


Delphi-Quelltext
1:
2:
3:
if TObject(Node.Data) is TData then begin
  TData(Node.Data).{...}
end;

dann mach ich das jetzt so :lol:

und was wäre ein dynamisches "casten" :?:


datensender - Do 25.09.03 12:26

"as" ist in Delphi u.A. für dynamische Typumwandlung gedacht und
das funktioniert dann auch nur im Zusammenhang mit Objekten,
weil bestimmte Typinformationen für eine solche Umwandlung
notwendig werden (*1)...
Es findet zur Laufzeit eine Überprüfung auf eine sichere Umwandlung statt,
bei der (1:) die Klassenhierarchie des betroffenen Objektes durchsucht wird...
(_AsClass (oder auch _IsClass für "is") in der System.pas für Details)
Ist die Umwandlung mit "as" nicht möglich, wird eine
Exception ausgelöst...

D.h. also auch, dass für dyn. Casts extra Code erzeugt wird... (beim statischen Casten hingegen nicht.
Da wird dem Compiler nur klar gemacht, wie er was zu behandeln hat, soweit möglich...
dass eine Umwandlung möglich ist bedeutet aber nicht, dass
sie auch immer richtig ist... )


cbs - Do 25.09.03 13:28

also um das mal ein bischen zu verinnerlichen hab ich mal folgenden test gemacht

Button1Click ist einem Button als OnClick ereigniss zugewiesen

Delphi-Quelltext
1:
2:
3:
4:
procedure TFormMain.Button1Click(Sender: TObject);
begin
  ShowMessage(TButton(Sender).Caption);
end;

die beschriftung wird korrekt angezeigt

jetzt das selbe mit as

Delphi-Quelltext
1:
2:
3:
4:
procedure TFormMain.Button1Click(Sender: TObject);
begin
  ShowMessage((Sender as TButton).Caption);
end;

auch hier wird die beschriftung korrekt angezeigt

dann hab ich mal spassens halber ein Edit-Feld auf mein Formular platziert und im OnClick ereigniss die selbe prozedure zugewiesen

Delphi-Quelltext
1:
2:
3:
4:
procedure TFormMain.Button1Click(Sender: TObject);
begin
  ShowMessage(TButton(Sender).Caption);
end;

zeigt mir den korrekten aktuellen Text vom Edit-Feld an :!:
wie geht das :?: TEdit hat keine eigenschaft namens caption

bei

Delphi-Quelltext
1:
2:
3:
4:
procedure TFormMain.Button1Click(Sender: TObject);
begin
  ShowMessage((Sender as TButton).Caption);
end;

wird wie du sagst eine exception ausgelöst


maximus - Do 25.09.03 13:56

@Caption: das liegt daran, dass die propertie 'caption' und 'text' beide die selben functionen benutzen:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
TControl = class(TComponent)
  property Caption: TCaption read GetText write SetText stored   IsCaptionStored;
...
  property Text: TCaption read GetText write SetText;
...
end;


und da bei dem typeCast nur auf ein feld, eines gemeinsamen vorfahren, zugegriffen wird, ist alles in bester ordnung mit dem illegalen typeCast!

hab mal gehört, dass is und as auslaufmodelle sind und nicht mehr benutzt werden sollten. Ich benutz sowieso immer TclassX.inheritedFrom(TBla...) und dann statische casts :wink:


cbs - Do 25.09.03 14:23

maximus hat folgendes geschrieben:
liegt daran, dass die propertie 'caption' und 'text' beide die selben functionen benutzen

alles klar :wink:

maximus hat folgendes geschrieben:
hab mal gehört, dass is und as auslaufmodelle sind und nicht mehr benutzt werden sollten. Ich benutz sowieso immer TclassX.inheritedFrom(TBla...)


die OH sagt dazu aber folgendes

OnlineHilfe hat folgendes geschrieben:
InheritsFrom entspricht dem Delphi-Operator is

also doch nicht so ganz ein "auslaufmodell" :wink: