AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Object-Pascal / Delphi-Language Kann operator "as T" fehlschlagen, wenn operator "is T" OK war ?
Thema durchsuchen
Ansicht
Themen-Optionen

Kann operator "as T" fehlschlagen, wenn operator "is T" OK war ?

Ein Thema von Rollo62 · begonnen am 28. Jul 2022 · letzter Beitrag vom 28. Jul 2022
Antwort Antwort
Rollo62

Registriert seit: 15. Mär 2007
4.116 Beiträge
 
Delphi 12 Athens
 
#1

Kann operator "as T" fehlschlagen, wenn operator "is T" OK war ?

  Alt 28. Jul 2022, 12:47
Delphi-Version: 11 Alexandria
Hallo zusammen,

ich frage mich generell wie weit man sich auf das "is" - "as" Schema verlassen kann.
Ist das für alle möglichen Fälle 100% wasserdicht ( außer Multithread natürlich ), oder
muss man das unter bestimmten Umständen besser in try-except kapseln um Exceptions abzufangen ?

Es geht um ungefähr folgendes Konstrukt, hier mal beispielhaft sowas wie die Übergabe von Sender:

Delphi-Quellcode:
procedure TMyClass.TestParamter( const ASender : TObject );
var
    LBtn1 : TButton;
    LBtn2 : TSpeedButton;
begin
    if not Assigned( ASender ) then
        Exit; //<== GUARD ==============================

    if ( ASender is TButton ) then
    begin
        LBtn1 := ASender as TButton; // Ist der Zugriff immer Valide, wenn der "is" operator True geliefert hat ?
    end;

    if ( ASender is TSpeedButton ) then
    begin
        LBtn2 := ASender as TSpeedButton; // Ist der Zugriff immer Valide, wenn der "is" operator True geliefert hat ?
    end;

    ...

end;
Die Frage ist: Kann es bestimmte Objekt-Konstruktionen geben, welche bei der Umwandlung "ASender as T;" krachen können ?
Ich blende MultiThread-Zugriffe hier mal aus und dass jemand von außen das Object zerstören kann bevor es benutzt wird.

Und wenn es Problemfälle geben kann, welches wäre dann die problematische Konstellation bei der Klasse ( Generics, InterfacedObject, ... ) ?

Ich vermute die Antwort ist: Ja der Zugriff ist 100% sicher,
oder könnte es doch ein "Aber" geben

Geändert von Rollo62 (28. Jul 2022 um 12:50 Uhr)
  Mit Zitat antworten Zitat
mkinzler
(Moderator)

Registriert seit: 9. Dez 2005
Ort: Heilbronn
39.861 Beiträge
 
Delphi 11 Alexandria
 
#2

AW: Kann operator "as T" fehlschlagen, wenn operator "is T" OK war ?

  Alt 28. Jul 2022, 13:00
as <Typ> impliziert is <Typ>. Wenn Du diese Überprüfung manuell ausführst kannst Du auch einen harten Cast ausführen.

Delphi-Quellcode:
if ( ASender is TButton ) then
begin
    LBtn1 := TButton(ASender); // Ist der Zugriff immer Valide, wenn der "is" operator True geliefert hat ?
end;
Markus Kinzler
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.475 Beiträge
 
Delphi 12 Athens
 
#3

AW: Kann operator "as T" fehlschlagen, wenn operator "is T" OK war ?

  Alt 28. Jul 2022, 13:05
Unter der Annahme, dass sich die Instanz zwischen is und as nicht ändert ist das sicher. Lediglich wenn die Instanz von Sender zwischenzeitlich freigegeben würde und an gleicher Stelle ein anderes Objekt erzeugt wird kann es krachen. Selbst wenn es nicht kracht hat man dann natürlich ein Problem mit einem nicht mehr existenten TButton. Das kann aber nur bei Multithreading passieren und dann muss man das eben anders abfangen. Eigentlich kann aber auch das nicht sein, da das Freigeben eines TButton außerhalb des MainThread eh nicht erlaubt ist.

Die entsprechenden Implementierungen sehen so aus (als Ergänzung zur Antwort von mkinzler):
Delphi-Quellcode:
function _IsClass(const Child: TObject; Parent: TClass): Boolean;
begin
  Result := (Child <> nil) and Child.InheritsFrom(Parent);
end;

function _AsClass(const Child: TObject; Parent: TClass): TObject;
begin
  Result := Child;
  if (Child <> nil) and not (Child is Parent) then
    ErrorAt(Byte(reInvalidCast), ReturnAddress);
end;
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

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

AW: Kann operator "as T" fehlschlagen, wenn operator "is T" OK war ?

  Alt 28. Jul 2022, 13:59
Wenn man das Objekt freigegeben hat (Free),
dann kann IS immernoch ein TRUE liefern, wenn im Speicher immernoch der Rumpf des Objektes existiert (nicht bereits überschrieben wurde).

AS würde dort auch noch funktionieren, aber der Zugriff auf dieses eigentlich "nicht mehr vorhandene" Objekt kann natürlich dennoch knallen.


Aber hier etwas beim Zugriff machen zu wollen ist nahezu unmöglich.
Der Fehler liegt diesbezüglich schon weit vorher, dort wo freigegeben, aber die Variable nicht geNILt wurde.




IS und AS verhalten sich nahezu gleich.
Alles was IS erlaubt, ist dann bei AS auch möglich.

Nur beim NIL verhalten sie sich unterschiedlich.
IS liefert bei NIL ein FALSE, während AS das NIL ohne Fehlermeldung durchlassen würde.

Delphi-Quellcode:
if (ASender is TButton) or not Assigned(ASender) then
begin
  LBtn1 := TButton(ASender); // oder LBtn1 := (ASender as TButton) ... funktioniert immer, aber ist "unnötig", da IS bereits geprüft hatte
end;
$2B or not $2B

Geändert von himitsu (28. Jul 2022 um 14:03 Uhr)
  Mit Zitat antworten Zitat
Rollo62

Registriert seit: 15. Mär 2007
4.116 Beiträge
 
Delphi 12 Athens
 
#5

AW: Kann operator "as T" fehlschlagen, wenn operator "is T" OK war ?

  Alt 28. Jul 2022, 15:10
Das ist gut, danke für die Bestätigungen.

@mkinzler
Das "as" auch "is" macht war mir so im Detail nicht bewusst, aber es macht ja für mich keinen Unterschied wenn ich eine Exception im Vorfeld verhindern möchte.

Der eigentliche Übeltäter ist wohl ErrorAt():
Delphi-Quellcode:
  if (Child <> nil) and not (Child is Parent) then
    ErrorAt(Byte(reInvalidCast), ReturnAddress);
Ich wollte mir da was Generisches bauen, so in der Art, und frage mich immer noch ob es den ganzen Aufwand wert ist:

Delphi-Quellcode:

type // Safe type cast from TObject to a derived class, if available, w/o crash
    TMyCast<T : class> = class sealed
        class function CanCast( Sender : TObject ) : Boolean;
        class function TryCast( Sender : TObject; var ACasted : T ) : Boolean;
    end;

...

{ TMyCast<T> }

class function TMyCast<T>.CanCast( Sender : TObject ) : Boolean;
begin
    Result := False;

    if not Assigned( Sender ) then
    begin
        Exit; //<== GUARD ======================================================
    end;

    if not ( Sender is T ) then
    begin
        Exit; //<== GUARD ======================================================
    end;

    Result := True;
end;


class function TMyCast<T>.TryCast( Sender : TObject; var ACasted : T ) : Boolean;
begin
    ACasted := nil;
    Result := False;

    if not Assigned( Sender ) then
    begin
        Exit; //<== GUARD ======================================================
    end;

    if not ( Sender is T ) then
    begin
        Exit; //<== GUARD ======================================================
    end;

    ACasted := Sender as T;
    Result := True;
end;
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

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

AW: Kann operator "as T" fehlschlagen, wenn operator "is T" OK war ?

  Alt 28. Jul 2022, 15:50
Wenn es bei ErrorAt knallt, dann stimmt der Typ in T nicht mit dem im Sender übererin.

Wenn ich alles rauswerfe, was doppelt ist, da IS es bereits macht (GUARD), dann bleibt das übrig:
Delphi-Quellcode:
class function TMyCast<T>.CanCast( Sender : TObject ) : Boolean;
begin
  Result := Sender is T;
end;

class function TMyCast<T>.TryCast( Sender : TObject; var ACasted : T ) : Boolean;
begin
  ACasted := nil;
  Result := Sender is T;
  if Result then
    ACasted := Sender as T; // oder := T(Sender);
end;
$2B or not $2B
  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 23:41 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