AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren

as

Ein Thema von Popov · begonnen am 30. Nov 2012 · letzter Beitrag vom 30. Nov 2012
Antwort Antwort
Popov
(Gast)

n/a Beiträge
 
#1

as

  Alt 30. Nov 2012, 17:58
Ich bin leicht verwirrt. Natürlich kenne ich as und auch den Unterschied zwischen TTest(abc) und (abc as TTest) . Vor allem die Laufzeitprüfung und die nette Fehlermeldung. Ich gebe offen zu, dass ich as sehr selten nutze, da ich von meiner Einstellung her keine Überraschungen mag und somit auch keine Fehlermeldungen, ausgenommen meine. Das Objekt wird bei mir also zuerst überprüft und evtl. eine Alternative gewählt. Eine nette Fehlermeldung im Programm bringt mir nichts.

Trotzdem, ich hab gerade viel Code studiert und etliche Klassen und bin etwas verwirrt was den Mix angeht der vorherrscht. Einfach zu behaupten, dass wenn man sich sicher ist was kommt, dann TTest(abc) , wenn man sich überraschen will und eine nette Fehlermeldung haben will, dann (abc as TTest) . Guckt man sich so manchen Code an wird mal das eine mal das andere genommen. Den Sinn sehe ich oft nicht.

Wenn ich dann sowas sehe (nur mal als ein Beispiel von etlichen die mir heute aufgefallen sind), dann frage ich mich, hat es einen tieferen Sinn oder war der Programmierer an beiden Tagen lediglich unterschiedlich drauf. In der Regel gehe ich davon aus, dass ich nur den Sinn nicht erkenne

Delphi-Quellcode:
function TAbc.Get(Index: Integer): TGraphic;
begin
  Result := TGraphic(inherited Get(Index));
end;

procedure TAbc.Add(Item: TGraphic);
begin
  inherited Add(Item);
end;

function TDef.Get(Index: Integer): TBitmap;
begin
  Result := inherited Get(Index) as TBitmap;
end;

procedure TDef.Add(Item: TBitmap);
begin
  inherited Add(Item);
end;
  Mit Zitat antworten Zitat
Furtbichler
(Gast)

n/a Beiträge
 
#2

AW: as

  Alt 30. Nov 2012, 18:03
Es soll auch so etwas wie schlechte Programmierung geben.

Ich würde nur in einem Fall casten:

Delphi-Quellcode:
If MyInstance is TSomeObject then
  TSomeObject(MyInstance).DoSomeThing;
In allen anderen Fällen würde ich assen . Auch wenn es irgendwie klar ist, das das mit dem typecasting schon hinkommt, ist es dennoch nicht 'sicher', denn es kann theoretisch passieren, das die Typen eben nicht kompatibel sind.
  Mit Zitat antworten Zitat
Benutzerbild von stahli
stahli

Registriert seit: 26. Nov 2003
Ort: Halle/Saale
4.336 Beiträge
 
Delphi 11 Alexandria
 
#3

AW: as

  Alt 30. Nov 2012, 18:51
Man sollte natürlich immer sicher stellen, dass nur auf korrekte Typen gecastet wird.

if O is Txyz ... ist also nie verkehrt, um auch andere Fälle explizit zu behanden, bzw. ein falsches casten auszuschließen.
Aber auch nach bestandener Prüfung würde ich mit "as" casten. Das finde ich übersichtlicher, obwohl es dann eigentlich unnötig ist.

Wenn man ausschließen kann, dass falsche Klassen übergeben werden, dann kann man auch ohne vorherige Prüfung auch hart casten.
Ich würde aber dennoch immer "as" verwenden. Wenn sich doch mal ein Fehler einschleicht, erhält man wenigstens eine Fehlermeldung.

In neueren Versionen bieten sich in vielen Fällen natürlich alternativ die Generics an.
Stahli
http://www.StahliSoft.de
---
"Jetzt muss ich seh´n, dass ich kein Denkfehler mach...!?" Dittsche (2004)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

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

AW: as

  Alt 30. Nov 2012, 19:11
Zitat:
dass ich as sehr selten nutze, da ich von meiner Einstellung her keine Überraschungen mag und somit auch keine Fehlermeldungen
Da ist deine Einstellung genau falschrum, in Bezug auf deine Fehlererwartung.

AS wirf nur eine Exception, wenn sich die Objektinstanz nicht casten läßt, da das Objekt nicht dem dem angegebenen Typen entspricht, bzw. kein Nachfahre davon ist.

Und genau da ist diese Exception vollkommen in Ordnung.


Viel schlimmer wäre es, wenn du eine inkompatibles Objekt hart castes, was dann eventuell erst irgendwo später Exceptions wirft, z.B. wenn man auf etwas nicht existierendes, oder schlimmer noch auf etwas Falsches zugreift.
Oder ganz gemein, wenn der Zugriff keinen Fehler sofort wirft, aber natürlich auch nicht das macht, was man wollte ... da könnte ein Fehler oder vieleicht eine Exception erst viel später auftreten, was dann oftmals fast garnicht mehr nachvollziehbar ist.

Dort hast du es nämlich wesentlich schwerer, die (eigentliche) Ursache zu finden.

Also wenn Cast, dann gibt es nur zwei/drei mögliche Wege:
- man weiß 100,1 %-ig, daß wirklich immer nur dieser Typ ankommt, dann kann man bedenkenlos hart casten
- man kann nicht sicher sein, dann muß es geprüft werden

- weiß man den Typ nur nicht und will entscheidend reagieren, dann vorher mit IS prüfen und eine Auswahl treffen (danach kann gerne hart gekastet werden, da IS ja sicher geprüft hat)

- will/muß man auf etwas zugreifen, dann muß der Typ 100%ig sicher sein, dann womit man dort mit AS castet. (außer man hat vorher mit IS geprüft)
- wenn man mehrfach auf das Objekt zugreift, dann kann man vorher mit IS prüfen und wenn nicht, dann eine Exception werfen oder eine Assertion einsetzen (welches sich im Release deaktivieren läßt, wenn man den Code 100%ig auf Korrektheit geprüft hat)



PS:
IS ist eine fehlerlose Prüfung, welche einen Boolean zurückgibt, wenn das keine kompatible Instanz des gewünschten Typs ist.
AS ist ein prüfender Cast, welcher den gecastete Instanz-Zeiger zurückgibt und intern "theoretisch" ein IS aufruft.
obj.InheritsFrom entspricht quasi einem IS, auér daß dort natürlich eine Instanz (kein NIL) vorhanden sein muß, da man ja sonst die Methode nicht aufrufen kann.
(OK, man hätte das NIL bei Letzerem theoretisch im Code abfangen können, aber es gibt an der Stelle wenistens eine verständliche Zugriffsverletzung durch Lesen von Adresse $00000000)

Aber:
IS ist nur erfolgreich (True), wenn in der Variable ein Objekt enthalten ist (nicht NIL) und wenn es sich bei der Instanz um den gewünschten Typen oder einen Nachfahren handelt.
AS dagegen läßt auch NIL erfolgreich durch.

Also theoretisch müßte man beim AS auch noch mit Assigned prüfen,
aber praktisch ist es nicht so schlimm, wie es klingt, denn ein NIL erzeugt beim Zugriff eine (zuverlässige) definierte Fehlermeldung (siehe InheritsFrom), welche sich problemlos zurückverfolgen kann, da man nur von der Fehlerstelle zurückgehen muß, bis dahin von wo der Wert (nil) gekommen ist.


Delphi-Quellcode:
var
  Obj: TObject;
  X, Y: TList;
begin
  Obj := nil;

  if Obj is TList then
    ShowMessage('jupp');

  try
    if Obj.InheritsFrom(TList) then
      ShowMessage('jo');
  except
    on E: Exception do
      ShowMessage(E.ClassName + ': ' + E.Message);
  end;

  Y := TList(Obj);
  X := Obj as TList;

  if X = Y then ; // damit der Compiler nix wegoptimiert
end;


Ach ja, wenn man ganz paranoid ist, dann darf man gerne alle eingehenden Parameter prüfen,
aber da Delphi eine recht strikte Typenprüfung besitzt, darf man gerne davon ausgehen, daß ein Parameter/Variable/Feld/... mindestens diesem Typen entspricht oder nil ist.
Falls doch irgendwo ein Idiot absichtlich, bzw. grob fahrlässig, diese Typenprüfung umgeht und ein total inkompatibles Objekt dort reinhackt, dann ist das halt so und und man darf es beruhigt unkontroliert knallen lassen.

Soll heißen: Wenn man eine Variable TList hat, dann ist dort einfach immer nur mindestens eine TList (oder Nachfahre) oder Nichts (nil) drinnen
und Falls doch mal ein TEdit da reingeraten ist ... Pech.
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests

Geändert von himitsu (30. Nov 2012 um 19:22 Uhr)
  Mit Zitat antworten Zitat
Popov
(Gast)

n/a Beiträge
 
#5

AW: as

  Alt 30. Nov 2012, 20:02
Ich würde nur in einem Fall casten:
...
In allen anderen Fällen würde ich assen
Das entspricht eigentlich auch meiner Vorgehensweise. Ich prüfe alles stets zuerst, somit weiß ich womit ich arbeite. Wozu dann also as wenn ich die Klasse kenne.

Wobei wenn ich mir jetzt mein Beispiel angucke, dann ist es evtl. nicht glücklich gewählt. Ich hab mich zu stark von - zwei gleiche Aktionen, zwei Vorgehensweisen - einnehmen lassen. Durch den Zugriff auf die Vorgängerklasse gibt man die Kontrolle aus der Hand. Nun ja, wenn man TBitmap rein stopft, sollte eigentlich auch TBitmap raus kommen. Aber ok, man bekommt etwas von einer anderen Funktion geliefert. In diesem besonderen Fall ist der Fall eigentlich klar. Schlechtes Beispiel.

Mal sehen, vielleicht finde ich bessere Beispiele.

Da ist deine Einstellung genau falschrum, in Bezug auf deine Fehlererwartung.
Also ich weiß nicht ob meine Einstellung falsch ist, vielleicht haben wir nur unterschiedliche Vorstellungen von den Ausgangsvoraussetzungen. Ok, das Beispiel ist vielleicht nicht glücklich gewählt, aber was bringt dem Nutzer meines Programms eine schöne Fehlermeldung. Besser ist es gar nicht erst so weit kommen zu lassen, wenn es geht.

Aber wie bereits gesagt, denn Unterschied kenne ich. Nur gehe ich bei solchen Beispielen wie oben zuerst davon aus, dass es schon seine Richtigkeit hat.
  Mit Zitat antworten Zitat
Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

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 03:25 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