Autor Beitrag
FD-83
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 49



BeitragVerfasst: So 27.02.05 17:11 
Wo genau liegt eigentlich der Unterschied zwischen den beiden TypeCast Varianten?

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
procedure TForm1.Button1Click(Sender: TObject);
begin
  (Sender as TButton).Caption := 'klick';
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  TButton(Sender).Caption := 'klack';
end;

Funktionieren tut ja beides. Sind das 2 Schreibweisen für die gleiche Sache oder gibts wirklich einen Unterschied?

Gruss Frederik
Larus
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 431



BeitragVerfasst: So 27.02.05 17:37 
Was macht das überhaupt?
FD-83 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 49



BeitragVerfasst: So 27.02.05 17:59 
Das nennt man Casting. Damit kann man Objekte von einem Klassen- oder interfaceTyp in einen anderen Umwandeln. Vorrausgesetzt sie sind in der selben Vererbungshirachie bzw. implementieren das entsprechende Interface.

Im Beispiel oben hast du den Sender des Ereignisses (also den Button) nur als TObject vorliegen. Ein TObject hat aber keine Eigenschaft Caption. Daher muss man die TObject Variable erst in eine vom Typ TButton casten. Das funktioniert, weil ein TButton (so wie alle anderen Klassen) vom Typ TObject abstammen.

So ganz grob. Richtig verstehen kann man das nur, wenn man sich etwas mehr mit OOP beschäftigt...

Gruß
Frederik
Larus
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 431



BeitragVerfasst: So 27.02.05 18:13 
achso also mit anderen Worten.... Nur der Button der gerade auf diese Funktion zugreift wird umbenannt? (Wie im Beispiel)
delfiphan
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2684
Erhaltene Danke: 32



BeitragVerfasst: So 27.02.05 18:29 
Larus hat folgendes geschrieben:
achso also mit anderen Worten.... Nur der Button der gerade auf diese Funktion zugreift wird umbenannt? (Wie im Beispiel)

Mit anderen Worten? Die Aussage ist oben nirgends enthalten. Es wird auch nichts umbenannt sondern der Typ wird gecastet.

TButton(Sender) ist ähnlich wie wenn man Byte('A') schreibt, um raus zu finden welche Nummer in der Ascii-Tabelle das Zeichen 'A' hat. TButton(Sender) heisst einfach, was immer bei der Speicheradresse für Sender ist, soll jetzt ein TButton sein.
Ich denk in Delphi 1 kannst du sogar String(F) schreiben (meinetwegen "String((@F)^)" in späteren Versionen), wobei F ein real ist. Da bekommst du dann ziemlichen Müll raus. Da musst du aufpassen.
"Sender as TButton" liefert eine Referenz auf "Sender" mit dem Typ TButton. Kann "Sender" gar kein TButton sein, dann gibt es eine Exception. "Sender as TButton" erzeugt mehr Code als "TButton(Sender)". Das "as" geht natürlich nur mit Klassen.


Zuletzt bearbeitet von delfiphan am So 27.02.05 18:39, insgesamt 1-mal bearbeitet
wulfskin
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1349
Erhaltene Danke: 1

Win XP
D5 Pers (SSL), D2005 Pro, C, C#
BeitragVerfasst: So 27.02.05 18:32 
Larus hat folgendes geschrieben:
achso also mit anderen Worten.... Nur der Button der gerade auf diese Funktion zugreift wird umbenannt? (Wie im Beispiel)
Es wird die Beschriftung des Buttons geändert, der gedrückt wurde und deshalb als Sender übergeben wurde.

Der Unterschied liegt daran, dass   (Sender as TPanel).Xy eine Fehlermeldung ausgibt, wenn Sender nicht vom Typ Panel ist. Der andere Typcast ignoriert das Stillschweigend und das Programm läuft weiter, sofern das Object die Eigenschaft trotzdem besitzt. Sie wird aber nicht geändert.

Gruß Hape!

//Edit: delfiphans Erklärung ist wohl besser ;)!

_________________
Manche antworten um ihren Beitragszähler zu erhöhen, andere um zu Helfen.


Zuletzt bearbeitet von wulfskin am So 27.02.05 18:35, insgesamt 1-mal bearbeitet
Larus
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 431



BeitragVerfasst: So 27.02.05 18:35 
gut zu wissen :) vieleicht kann man es irgentwanneinmal brauchen. :idea: außerdem is man ja ständig am weiterlesen und lernen :wink:
delfiphan
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2684
Erhaltene Danke: 32



BeitragVerfasst: So 27.02.05 18:42 
Übrigens, mit "if Sender is TButton" kannst du überprüfen, ob Sender ein TButton ist...
delfiphan
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2684
Erhaltene Danke: 32



BeitragVerfasst: So 27.02.05 18:46 
wulfskin hat folgendes geschrieben:
Der andere Typcast ignoriert das Stillschweigend und das Programm läuft weiter, sofern das Object die Eigenschaft trotzdem besitzt.

Darauf würde ich nicht wetten. Wenn du Glück hast, funktioniert's (z.B. bei .Caption oder .Text). Wenn du Pech hast, wirds einfach irgendwo in den Speicher geschrieben und du merkst es vielleicht nicht mal....
FD-83 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 49



BeitragVerfasst: Mo 28.02.05 00:59 
Also bei Klassen und Interfaces lieber is und as verwenden um Problemen vorzubeugen. So hab ichs bislang auch immer gemacht.

Gruß
Frederik
Motzi
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2931

XP Prof, Vista Business
D6, D2k5-D2k7 je Prof
BeitragVerfasst: Mo 28.02.05 01:17 
Der Operator as prüft intern per is ob das Objekt ein Nachfahre der entsprechenden Klasse ist. Daher sind zB Casts wie
ausblenden Delphi-Quelltext
1:
2:
 if xyObject is TxyClass then
   (xyObject as TxyClass)...

vollkommen unnötig, da die Überprüfung per is doppelt stattfindet. Hat man bereits selbst per is geprüft kann man ohne Probleme gleich direkt casten: TxyClass(xyObject)

interfaces dürfen nur per as gecastet werden, da dort eine Menge Hintergrundarbeit stattfindet (QueryInterface-Aufruf etc), und Delphi bei einem Typecast mittels as diese komplett transparent durchführt.

_________________
gringo pussy cats - eef i see you i will pull your tail out by eets roots!
IngoD7
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 629


D7
BeitragVerfasst: Mo 28.02.05 09:50 
Motzi hat folgendes geschrieben:
Der Operator as prüft intern per is ob das Objekt ein Nachfahre der entsprechenden Klasse ist.

Das liest man immer wieder. Ob es so ist, weiß ich nicht. Jedenfalls ist mir der Nutzen einer möglichen Überprüfung in as schleierhaft, denn sie ist nicht mit der Überprüfung mittels is zu vergleichen.

Man darf nämlich nicht den Umkehrschluss ziehen, dass wenn as verwendet wird, dann keine is-Abfrage mehr nötig ist!

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
//Code 1  ------- Kein Crash.
xyObject := nil;
if xyObject is TxyClass then      //is fängt auch nil ab.
  (xyObject as TxyClass).xxx;     //<--- Wird nicht ausgeführt.

//Code 2  ------- Kein Crash.
xyObject := nil;
if xyObject is TxyClass then      //is fängt auch nil ab.
  TxyClass(xyObject).xxx;         //<--- Wird nicht ausgeführt.

//Code 3  ------- Exception!
xyObject := nil;
(xyObject as TxyClass).xxx;       //Wird ausgeführt und fällt auf die Nase.

//Code 4  ------- Exception!
xyObject := nil;
TxyClass(xyObject).xxx;           //Wird ausgeführt und fällt auf die Nase.
Motzi
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2931

XP Prof, Vista Business
D6, D2k5-D2k7 je Prof
BeitragVerfasst: Mo 28.02.05 10:41 
IngoD7 hat folgendes geschrieben:
Das liest man immer wieder. Ob es so ist, weiß ich nicht.

Es ist so, glaub mir.. ;) Wenn man bei einen Cast mittels as per Debugger in der System.pas mitschaut was da passiert findet man sich in einer Funktion "AsClass" wieder, die sowohl eine Pascal, als auch eine ASM Umsetzung hat. Die Pascal-Variante schaut so aus:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
begin
  Result := Child;
  if not (Child is Parent) then
    Error(reInvalidCast);   // loses return address
end;


Was deinen Fall 3 betrifft:
ausblenden Delphi-Quelltext
1:
2:
3:
//Code 3  ------- Exception!
xyObject := nil;
(xyObject as TxyClass).xxx;       //Wird ausgeführt und fällt auf die Nase.

Wenn man sich vom Pascal-Code der Funktion AsClass ausgeht hast du recht, dann gibt es eine Exception. Die ASM-Umsetzung geht allerdings ein bisschen anders vor, indem sie als erstes überprüft ob die zu castende Objektreferenz nil ist und liefert in diesem Fall keine Exception.

_________________
gringo pussy cats - eef i see you i will pull your tail out by eets roots!
retnyg
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2754

SNES, GB, GBA, CPC, A500, 486/66, P4/3.0HT: NintendOS, AmigaOS, DoS
Delphi 5, Delphi 7
BeitragVerfasst: Mo 28.02.05 11:11 
und wie bringt man dem compiler bei dass er die asm-version aussführt ? ein DEFINE irgendwo ?
IngoD7
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 629


D7
BeitragVerfasst: Mo 28.02.05 11:17 
Motzi hat folgendes geschrieben:
Was deinen Fall 3 betrifft:
ausblenden Delphi-Quelltext
1:
2:
3:
//Code 3  ------- Exception!
xyObject := nil;
(xyObject as TxyClass).xxx;       //Wird ausgeführt und fällt auf die Nase.

Wenn man sich vom Pascal-Code der Funktion AsClass ausgeht hast du recht, dann gibt es eine Exception. Die ASM-Umsetzung geht allerdings ein bisschen anders vor, indem sie als erstes überprüft ob die zu castende Objektreferenz nil ist und liefert in diesem Fall keine Exception.
Was soll mir das mit der ASM-Umsetzung nun sagen? Delphi jedenfalls geht dann wohl vom Pascal-Code aus, denn die Exception kommt.
Motzi
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2931

XP Prof, Vista Business
D6, D2k5-D2k7 je Prof
BeitragVerfasst: Mo 28.02.05 11:41 
Die Pascal und ASM-Umsetzung werden durch Compiler-Schalter getrennt:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
{$IFDEF PUREPASCAL}
  // Pascal-Umsetzung
{$ELSE}
  // ASM-Umsetzung
{$ENDIF}

Da das Symbol PUREPASCAL aber nicht definiert ist wird die ASM-Umsetzung ausgeführt... (so ist zumindest die Situation in meinem D6 Prof)

_________________
gringo pussy cats - eef i see you i will pull your tail out by eets roots!
IngoD7
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 629


D7
BeitragVerfasst: Mo 28.02.05 11:52 
Zitat:
Da das Symbol PUREPASCAL aber nicht definiert ist wird die ASM-Umsetzung ausgeführt... (so ist zumindest die Situation in meinem D6 Prof)

Nun mal Hand auf's Herz: :wink:

Folgendes führt bei dir also nicht zur Exception???
ausblenden Delphi-Quelltext
1:
2:
3:
4:
var Komp : TComponent;
...
Komp := nil;
(Komp as TEdit).Clear;
Motzi
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2931

XP Prof, Vista Business
D6, D2k5-D2k7 je Prof
BeitragVerfasst: Mo 28.02.05 12:04 
Genau so schauts aus..! ;) Extra getestet und mit dem Debugger Schritt für Schritt durchgegangen um zu sehen was da passiert. Hab mir auch mal meine eigene AsClass-Funktion mit dem PurePascal-Code gemacht und die hat (logischerweise) schon zu einer Exception geführt.

_________________
gringo pussy cats - eef i see you i will pull your tail out by eets roots!
delfiphan
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2684
Erhaltene Danke: 32



BeitragVerfasst: Mo 28.02.05 12:09 
Purepascal müsste doch genau dasselbe tun wie die asm Version, einfach nicht mit der gleichen Effizienz. Kann doch nicht sein, dass die sich anders verhalten?!? Ich zitiere aus der Hilfe:
"At runtime, object must be (...), or be nil; otherwise an exception is raised."
Da steht nix davon, dass bei nil auch ne Exception geraised wird...
(Ich glaub es euch natürlich schon, finde es einfach ein wenig merkwürdig)
IngoD7
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 629


D7
BeitragVerfasst: Mo 28.02.05 12:19 
Motzi hat folgendes geschrieben:
Genau so schauts aus..! ;)
Das'n Ding. Habe D7E. Da wirft er die Exception. Ich weiß aber nicht, welchen Teil er ausführt, da ich mich mit dem Debugger nicht so gut auskenne. Eine "Extra-PurePascal-Definition" kann ich jedenfalls nirgends erkennen.