Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - Is-Operator


Mitmischer 1703 - So 30.11.08 13:30
Titel: Is-Operator
Wofür gibt es den Is-Operator?

Edit: Arrgh *drauf geh* Ich hab meinen 400.Post verpasst! :schmoll: *schmoll*


jaenicke - So 30.11.08 14:34

Damit prüfst du ob ein Objekt ein bestimmter Typ ist. Zum Beispiel wird in den ganzen Events immer Sender: TObject mit übergeben. Darin steckt das Objekt, das dieses Ereignis ausgelöst hat. Bei einem Buttonclick also der Button, von dem es kommt. Wenn du jetzt aber das selbe Event von einem TButton und einem TBitButton aufrufst, kannst du nicht einfach nach TButton casten, an der Stelle musst du dann feststellen was da als Objekt übergeben wurde.

Praktisches Beispiel:
Nimm mal zwei Buttons und schreibe beim ersten im OnClick:

Delphi-Quelltext
1:
(Sender as TButton).Caption := 'geklickt';                    
Jetzt gehe in den Objektinspektor und weise dem OnClick des zweiten Buttons manuell das Event des ersten zu. Das Ergebnis ist, dass du nur eine Prozedur zur Behandlung beider Klicks hast.

Du kannst diese Methode aber auch selbst aufrufen mit Button1Click(Button1);. Du kannst dort aber auch ein anderes Objekt angeben und dann im Klick unterscheiden:

Delphi-Quelltext
1:
2:
3:
4:
if Sender is TButton then
  (Sender as TButton).Caption := 'geklickt'
else
  ShowMessage('Anders aufgerufen');
Schreibe das einmal in deine OnClick Routine, erstelle einen weiteren Button und schreibe dort hinein:

Delphi-Quelltext
1:
Button1Click(Form1);                    

Ergebnis: Wird das Button1Click bei dem Event aufgerufen durch die beiden Buttons, dann wird deren Caption geändert, rufst du es manuell durch den dritten Button auf, dann übergibst du keinen Button und deshalb kommt die MessageBox.


Mitmischer 1703 - So 30.11.08 15:06

Aber kann man nicht mit

Delphi-Quelltext
1:
if Button1.Type = TButton                    

(oder etwas ähnlichem) überprüfen?

Die Sache mit dem as-Operator versteh ich aber nicht ganz... Nimmt man damit eine Typverwandlung vor. Also: Tu so als ob Sender gleich TButton wäre und führe dann >>bla, bla<< aus - Und bla, bla ist spezielle Funktion von TButton?!:?:?:?


jaenicke - So 30.11.08 15:24

user profile iconMitmischer 1703 hat folgendes geschrieben Zum zitierten Posting springen:
Aber kann man nicht mit

Delphi-Quelltext
1:
if Button1.Type = TButton                    

(oder etwas ähnlichem) überprüfen?
Dabei lässt du außer Acht, dass eine Klasse oft mehrere Vorfahren hat. So kannst du nur die letzte prüfen, nicht aber ob es sich zum Beispiel um einen Nachfahren von TControl oder TWinControl handelt. Du kannst mit is das prüfen um etwas mit mehreren Komponententypen zu machen. Zum Beispiel Visible ändern, egal ob es ein TButton oder ein TMemo ist.
Nebenbei: Es heißt ClassType ;-).

Als Beispiel, TButton und TMemo mit folgender OnClick-Routine:

Delphi-Quelltext
1:
2:
  if Sender is TWinControl then
   TWinControl(Sender).Visible := False;
Mit ClassType könntest du nur auf den speziellen Typ prüfen, nicht aber auf den gemeinsamen Vorfahren TWinControl.

An dieser Stelle kannst du mit TWinControl(Sender) direkt casten, weil du ja vorher geprüft hast, dass es sich um diesen Typ handelt.
Wenn du as benutzt wird vorher geprüft ob der Typecast überhaupt möglich ist.

user profile iconMitmischer 1703 hat folgendes geschrieben Zum zitierten Posting springen:
Die Sache mit dem as-Operator versteh ich aber nicht ganz... Nimmt man damit eine Typverwandlung vor. Also: Tu so als ob Sender gleich TButton wäre und führe dann >>bla, bla<< aus - Und bla, bla ist spezielle Funktion von TButton?!:?:?:?
Richtig, der in einer allgemeinen Variable z.B. vom Typ TObject gespeichert ist, soll wieder als TButton behandelt werden, denn wenn du die Variable ohne Typecast benutzt, dann weiß Delphi ja nicht, dass es ein Button ist und du kannst die speziellen Eigenschaften und Methoden eines Buttons nicht benutzen.


alzaimar - So 30.11.08 15:30

user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:

Delphi-Quelltext
1:
2:
if Sender is TButton then
  (Sender as TButton).Caption := 'geklickt'

Hier ist der 'as' Operator überflüssig bzw. zu viel des Guten, dann 'Sender' IST ja auf jeden Fall ein 'TButton'. Hier reicht ein einfaches Typecasting, denn 'as' ist eine relativ komplexe Operation mit Overhead. Hier reicht also (aber *nur* wegen der Prüfung mittels 'is'):

Delphi-Quelltext
1:
2:
if Sender is TButton then
  TButton(Sender).Caption := 'geklickt'


jaenicke - So 30.11.08 15:33

Nachdem ich vorher as gerade benutzt hatte wollte ich dort nicht gleich was anderes benutzen, das habe ich dann beim nächsten Mal ja gemacht ;-).


alzaimar - So 30.11.08 15:42

Stimmt. :zustimm: Wollte halt auch mal was sagen...


Mitmischer 1703 - So 30.11.08 15:59

user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:

user profile iconMitmischer 1703 hat folgendes geschrieben Zum zitierten Posting springen:
Die Sache mit dem as-Operator versteh ich aber nicht ganz... Nimmt man damit eine Typverwandlung vor. Also: Tu so als ob Sender gleich TButton wäre und führe dann >>bla, bla<< aus - Und bla, bla ist spezielle Funktion von TButton?!:?:?:?
Richtig, der in einer allgemeinen Variable z.B. vom Typ TObject gespeichert ist, soll wieder als TButton behandelt werden, denn wenn du die Variable ohne Typecast benutzt, dann weiß Delphi ja nicht, dass es ein Button ist und du kannst die speziellen Eigenschaften und Methoden eines Buttons nicht benutzen.

Und wenn Sender KEIN Button ist und wir die Prüfung mit is nicht da wäre, was passiert dann?


jaenicke - So 30.11.08 16:04

Dann gibt es bei einem harten Typecast TButton(Sender) vermutlich eine Zugriffsverletzung und bei Verwendung des as-Operators (Sender as TButton) eine Exception (und deshalb eine Fehlermeldung) EInvalidTypecast oder so, dass die Typumwandlung nicht möglich ist.


Mitmischer 1703 - So 30.11.08 16:07

user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Dann gibt es bei einem harten Typecast TButton(Sender) vermutlich eine Zugriffsverletzung und bei Verwendung des as-Operators (Sender as TButton) eine Exception (und deshalb eine Fehlermeldung) EInvalidTypecast oder so, dass die Typumwandlung nicht möglich ist.

:shock: Und wofür braucht man as, wenn man doch is oder TEdit(Sender) hat?!


jaenicke - So 30.11.08 16:25

Nun ja, wenn du as benutzt ohne vorher mit is zu prüfen, dann kommt im Fehlerfalle eine entsprechende aussagekräftige Fehlermeldung, wie gesagt. Wenn man sich sicher ist, dass der Typecast erfolgreich ist, z.B. weil man es mit is überprüft hat, dann kann man natürlich auch direkt casten mit TButton(Sender).
Problematisch ist dann nur, wenn doch ein falscher Cast passiert, denn dann kommt bei TButton(Sender) eine erstmal nichtsagende Zugriffsverletzung.


Mitmischer 1703 - So 30.11.08 16:50

user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Nun ja, wenn du as benutzt ohne vorher mit is zu prüfen, dann kommt im Fehlerfalle eine entsprechende aussagekräftige Fehlermeldung, wie gesagt. Wenn man sich sicher ist, dass der Typecast erfolgreich ist, z.B. weil man es mit is überprüft hat, dann kann man natürlich auch direkt casten mit TButton(Sender).
Problematisch ist dann nur, wenn doch ein falscher Cast passiert, denn dann kommt bei TButton(Sender) eine erstmal nichtsagende Zugriffsverletzung.


Ah, ok!

Und wie prüft man mit is, wenn man nicht den Typ sondern den Namen oder sonst etwas prüfen will. So?


Delphi-Quelltext
1:
if Button1.Name is "Bla"                    


Wie wird denn dann auf dei "Vorgänger" geprüft?!


jaenicke - So 30.11.08 16:57

Bei button1 kennst du ja den Typ, es geht ja um Sender oder andere Variablen, die einen allgemeineren Typ haben als den um den es geht. Wenn du den Namen prüfen willst, dann gehst du ja davon aus, dass es sich um eine Komponente handelt, also musst du darauf prüfen und kannst dann das Objekt als TComponent behandeln. In TComponent ist u.a. die Eigenschaft Name deklariert.

Delphi-Quelltext
1:
2:
  if Sender is TComponent then
    ShowMessage(TComponent(Sender).Name);


Mitmischer 1703 - So 30.11.08 16:59

user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Bei button1 kennst du ja den Typ, es geht ja um Sender oder andere Variablen, die einen allgemeineren Typ haben als den um den es geht. Wenn du den Namen prüfen willst, dann gehst du ja davon aus, dass es sich um eine Komponente handelt, also musst du darauf prüfen und kannst dann das Objekt als TComponent behandeln. In TComponent ist u.a. die Eigenschaft Name deklariert.

Delphi-Quelltext
1:
2:
  if Sender is TComponent then
    ShowMessage(TComponent(Sender).Name);

Ok! Danke!!!


delfiphan - So 30.11.08 21:10

user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Dann gibt es bei einem harten Typecast TButton(Sender) vermutlich eine Zugriffsverletzung

TButton(Sender).Visible würde wohl noch knapp gut gehen, auch wenn Sender ein TEdit wäre, solange Visible bei einem gleichen Vorfahren definiert ist. Aber das ist absolut schlecht und nicht zu empfehlen. Man sollte nie direkt casten, wenn der entsprechende Cast per as fehlschlagen könnte. Es gibt da einige ganz wenige Stellen im VCL Code, wo dies nicht gilt, aber zu empfehlen ist das so oder so nicht.


galagher - Mo 01.12.08 19:44

user profile icondelfiphan hat folgendes geschrieben Zum zitierten Posting springen:
TButton(Sender).Visible würde wohl noch knapp gut gehen, auch wenn Sender ein TEdit wäre, solange Visible bei einem gleichen Vorfahren definiert ist. Aber das ist absolut schlecht und nicht zu empfehlen. Man sollte nie direkt casten, wenn der entsprechende Cast per as fehlschlagen könnte. Es gibt da einige ganz wenige Stellen im VCL Code, wo dies nicht gilt, aber zu empfehlen ist das so oder so nicht.

Um bei obigem Beispiel zu bleiben:
Ich mache das - TButton(Sender) - eigentlich immer dann so, wenn es definitiv immer nur ein TButton sein kann. Wenn mehrere Komponenten-Typen als Sender in Frage kommen, ist mir klar, dass man das berücksichtigen sollte, damit's nicht irgendwann kracht.

Aber Sender as verwende ich nicht (mehr).